除了 Spring context 之外还需要导入以下几个包:
<dependency>
<groupId>com.mchangegroupId>
<artifactId>c3p0artifactId>
<version>0.9.5.2version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.1.2.RELEASEversion>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.44version>
dependency>
首先需要一个配置类,然后使用注解@EnableTransactionManagement
开启事务控制,同时需要在容器中导入 事务管理器 PlatformTransactionManager
。
@Configuration
@ComponentScan("top.wsuo.tx")
@EnableTransactionManagement
public class TxConfig {
/**
* 配置数据源
*
* @return 数据源
* @throws Exception 异常
*/
@Bean
public DataSource dataSource() throws Exception {
InputStream is = this.getClass().getResourceAsStream("/db.properties");
Properties properties = new Properties();
properties.load(is);
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(properties.getProperty("db.user"));
dataSource.setPassword(properties.getProperty("db.password"));
dataSource.setJdbcUrl(properties.getProperty("db.url"));
dataSource.setDriverClass(properties.getProperty("db.driver"));
return dataSource;
}
/**
* 将 template 放入容器中
*
* @return JdbcTemplate
* @throws Exception 异常
*/
@Bean
public JdbcTemplate jdbcTemplate() throws Exception {
return new JdbcTemplate(dataSource());
}
/**
* 配置事务管理器
*
* @return 返回事务管理器
* @throws Exception 异常
*/
@Bean
public PlatformTransactionManager platformTransactionManager() throws Exception {
return new DataSourceTransactionManager(dataSource());
}
}
在 Service
层调用的时候,只要在需要事务控制的方法上面添加一个 @Transactional
注解即可。
@Service
public class UserService {
private final UserDao userDao;
public UserService(@Autowired UserDao userDao) {
this.userDao = userDao;
}
// 标注事务: 出现异常会自动回滚
@Transactional
public void insertAccount() {
userDao.insert();
System.out.println("插入成功!");
}
}
于是 Spring 即可自动进行事务控制,体现在发生异常会自动回滚操作。
Spring 中大量使用 Enable*** 注解,他们的原理都类似,比如今天我们要分析的这个注解也是如此。
首先点进去该注解:
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
发现它导入了一个 TransactionManagementConfigurationSelector
组件,就是用来导入组件的,他是 ImportSelector
的实现类。
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
}
发现他就是两个判断,看他的模式是 PROXY
还是 ASPECTJ
,然后对应两个类或方法。
它的作用就是给容器中注册一个 InfrastructureAdvisorAutoProxyCreator
组件。
他只是利用后置处理器机制,在对象创建以后包装对象为一个代理对象,代理对象里有增强器,然后代理对象利用拦截器链执行方法,这里和 AOP 的原理一致,所以不解释了。
主要就是执行在 AbstractAutoProxyCreator
抽象类中实现的方法。
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource());
advisor.setAdvice(transactionInterceptor());
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
他会给容器中注册事务增强器,事务增强器要用事务注解的信息 AnnotationTransactionAttributeSource
解析注解。
还会设置一个 TransactionInterceptor
拦截器,它保存了事务的属性信息和事务管理器,同时他是一个 MethodInterceptor
。
在目标方法执行的时候会执行拦截器链,事务拦截器的功能是先获取事务相关的属性,再获取 PlatformTransactionManager
,如果事先没有执行任何 PlatformTransactionManager
,会从容器中按照类型获取。
然后执行目标方法,如果有异常,就获取事务管理器,利用事务管理回滚操作,如果正常利用事务管理器提交操作。