文章目录
本博客demo源码地址
https://github.com/suchahaerkang/spring-annotation.git
1 测试
首先向项目中引入数据源(c3p0),mysql连接驱动和 spring-jdbc的jar包
<!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
写个配置类
/**
* @description:
* @author: sukang
* @date: 2020-03-13 8:58
*/
@EnableTransactionManagement
@ComponentScan("com.wolfx.tx")
@Configuration
public class MainConfigOfTx {
/**
* @description: 配置数据源
* @param
* @return: javax.sql.DataSource
* @author: sukang
* @date: 2020/3/13 9:06
*/
@Bean
public DataSource dataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/dev");
dataSource.setUser("root");
dataSource.setPassword("root");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
return dataSource;
}
/**
* @description: 将JdbcTemplate组件注册到容器中去
* @param
* @return: org.springframework.jdbc.core.JdbcTemplate
* @author: sukang
* @date: 2020/3/13 10:06
*/
@Bean
public JdbcTemplate jdbcTemplate() throws PropertyVetoException {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
return jdbcTemplate;
}
/**
* @description: 将DataSourceTransactionManager的事务管理器注册到容器中去
* @param
* @return: org.springframework.transaction.PlatformTransactionManager
* @author: sukang
* @date: 2020/3/13 10:06
*/
@Bean
public PlatformTransactionManager transactionManager() throws PropertyVetoException {
return new DataSourceTransactionManager(dataSource());
}
}
写两个业务逻辑组件UserService和UserDao
/**
* @description:
* @author: sukang
* @date: 2020-03-13 9:09
*/
@Service
public class UserService {
@Autowired
private UserDao userDao;
@Transactional
public void insert(){
userDao.insert();
}
}
/**
* @description:
* @author: sukang
* @date: 2020-03-13 9:09
*/
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public void insert(){
String sql = "INSERT INTO `tb_user`(name,age) VALUES(?, ?)";
String str = UUID.randomUUID().toString().substring(0,5);
jdbcTemplate.update(sql, str, 19);
System.out.println("插入成功");
}
}
数据库中创建一个tb_user表
写个测试用例
@Test
public void test01(){
//创建IOC容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfTx.class);
//获取UserService组件
UserService userService = (UserService) applicationContext.getBean("userService");
userService.insert();
}
运行结果
数据库中有了一条数据
我们现在在UserService组件的insert()方法中修改一下代码,让其报异常,我们看看执行insert方法出现异常后,还能往数据库中插入数据吧?
/**
* @description:
* @author: sukang
* @date: 2020-03-13 9:09
*/
@Service
public class UserService {
@Autowired
private UserDao userDao;
@Transactional
public void insert(){
userDao.insert();
int i = 10/0;
}
}
运行结果
插入成功之后,然后就包异常了,我们再看看数据中的数据
数据库中还是只有一条数据,说明插入成功的那条数据在抛出异常之后回滚了。
申明式事务测试成功!想实现申明式事务必须要以下几步:
1) 在配置类上边标注@EnableTransactionManagement开启申明式事务
2) 在配置文件中必须要注册PlatformTransactionManager的事务管理器
3) 在需要事务处理的方法上加上@Transactional注解
2 源码分析
Spring的申明式事务用的是Spring的AOP技术,想了解Spring AOP技术可以了解一下我的这篇博客,我们现在从@EnableTransactionManagement这个注解作为入口,分析一下这个注解做了什么?
2.1 @EnableTransactionManagement
不了解@Import注解的作用的可以看一下我这篇文章
因为adviceMode默认是PROXY,所以@EnableTransactionManagement利用TransactionManagementConfigurationSelector组件给我们向容器注入了AutoProxyRegistrar和ProxyTransactionManagementConfiguration组件
下面我们分析一下这两个组件做了什么?
2.2 AutoProxyRegistrar
AutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口重写registerBeanDefinitions()方法会手动像容器中注册组件
跟源码,发现给我们手动注册了InfrastructureAdvisorAutoProxyCreator这个组件,这个组件又是做什么的呢?我们继续看源代码
最后发现InfrastructureAdvisorAutoProxyCreator
implements SmartInstantiationAwareBeanPostProcessor
, BeanFactoryAware
。看到这两个组件,我们就明白了,因为这篇文章我们详细的分析了其作用,这里我们就说了。这说明InfrastructureAdvisorAutoProxyCreator这组件其实就是一个InstantiationAwareBeanPostProcessor后置处理器,会在所有bean初始化之后拦截,判断当前bean是否需要增强,如果需要的话,那么给其包装成一个代理对象。当使用这个bean的方法的时候,代理对象会拦截进行功能增强
。好了,我们知道@EnableTransactionManagement注解给我们注册的AutoProxyRegistrar这个组件是给我们注册了InfrastructureAdvisorAutoProxyCreator这个组件,并且知道了其作用。下面我们看一下@EnableTransactionManagement给我们注册的另外一个组件ProxyTransactionManagementConfiguration的作用
2.3 ProxyTransactionManagementConfiguration
我们看到ProxyTransactionManagementConfiguration就是个配置类,给我们向容器注册了BeanFactoryTransactionAttributeSourceAdvisor这个事务增强器,BeanFactoryTransactionAttributeSourceAdvisor设置了TransactionAttributeSource和TransactionInterceptor这两个属性
2.3.1 TransactionAttributeSource的作用
2.3.2 TransactionInterceptor的作用
我们发现TransactionInterceptor实现了MethodInterceptor接口,那么在执行目标方法的时候,会被执行拦截器链
,执行到这个事务拦截器会做一下操作