Spring注解驱动开发5:Spring声明式事务
Spring注解驱动开发系列:
Spring注解驱动开发5:Spring声明式事务
Spring声明式事务的使用
环境搭建
导入相关依赖
- 数据源
- 数据库驱动
- Spring-jdbc模块
pom文件增加如下:
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
编写User类:
@Component
public class User {
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
编写UserDao类:
@Repository
public class UserDao {
@Autowired
JdbcTemplate jdbcTemplate;
public void insert(User user) {
String sql = "INSERT INTO tb_user(username, age) VALUES(?, ?)";
jdbcTemplate.update(sql, user.getName(), user.getAge());
}
}
编写UserService类:
@Service
public class UserService {
@Autowired
UserDao userDao;
@Transactional
public void insertUser(User user) {
userDao.insert(user);
System.out.println("insert fini");
int i = 10/0;
}
}
编写配置类:
//配置类==配置文件
@Configuration
//开启自动包扫描,传入要扫描的包路径
@ComponentScan(basePackages = "com.lin.springL")
//开启注解事务支持
@EnableTransactionManagement
public class MainConfigure {
@Bean
public DataSource dataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser("root");
dataSource.setPassword("root");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
编写测试类:
public class MainTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new
AnnotationConfigApplicationContext(MainConfigure.class);
UserService userService = applicationContext.getBean(UserService.class);
User user = new User("ddd", 34);
userService.insertUser(user);
}
}
执行MainTest类,会报错,查看数据库数据并没有插入数据,事务回滚成功。
总结
总的步骤如下:
- 在配置类上增加
@EnableTransactionManagement
注解开启事务管理。 - 向容器中注入PlatformTransactionManager的实现Bean。
- 在需要食物的方法上增加注解:
@Transactional
。
源码简单分析
还是以最重要的配置注解为开始查看:
进入到EnableTransactionManagement
类:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({TransactionManagementConfigurationSelector.class})
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default 2147483647;
}
关注到@Import({TransactionManagementConfigurationSelector.class})
向容器中注入了TransactionManagementConfigurationSelector这个类进入到这个类查看:
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
/**
* {@inheritDoc}
* @return {@link ProxyTransactionManagementConfiguration} or
* {@code AspectJTransactionManagementConfiguration} for {@code PROXY} and
* {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()}, respectively
*/
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
这个类实现了ImportSelector接口,看具体实现方法selectImports
,:
- 如果是PROXY,就返回注册AutoProxyRegistrar和ProxyTransactionManagementConfiguration。
- 如果是ASPECTJ,就返回注册TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME。
因为其默认AdviceMode mode() default AdviceMode.PROXY,所以是走PROXY这个分支,返回注册AutoProxyRegistrar和ProxyTransactionManagementConfiguration。
AutoProxyRegistrar
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
...
if (mode == AdviceMode.PROXY) {
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
...
里面方法最主要是的就是上面这行,注册自动代理创建类,也就是AOP,所以可以大胆猜测,Spring的事务管理通过AOP代理实现,例如回滚操作,在AOP的AfterThrow中回滚就可以达到抛出异常的时候会滚事务的操作。
本文来自博客园,作者:林老头儿,转载请注明原文链接:https://www.cnblogs.com/jinchengll/p/12922355.html