一.演示案例

 环境搭建:   1、导入相关依赖           数据源、数据库驱动、Spring-jdbc模块   2、配置数据源、JdbcTemplate(Spring提供的简化数据库操作的工具)操作数据   3、给方法上标注 @Transactional 表示当前方法是一个事务方法;   4、 @EnableTransactionManagement 开启基于注解的事务管理功能;           @EnableXXX   5、配置事务管理器来控制事务;           @Bean           public PlatformTransactionManager transactionManager()

@EnableTransactionManagement
@ComponentScan("com.atguigu.tx")
@Configuration
public class TxConfig {
	
	//数据源
	@Bean
	public DataSource dataSource() throws Exception{
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser("wisdomclass");
		dataSource.setPassword("susOn@20190916");
		dataSource.setDriverClass("com.mysql.jdbc.Driver");
		dataSource.setJdbcUrl("jdbc:mysql://xxxx:3306/intelligent_admin");
		return dataSource;
	}
	
	//
	@Bean
	public JdbcTemplate jdbcTemplate() throws Exception{
		//Spring对@Configuration类会特殊处理;给容器中加组件的方法,多次调用都只是从容器中找组件
		JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
		return jdbcTemplate;
	}
	
	//注册事务管理器在容器中
	@Bean
	public PlatformTransactionManager transactionManager() throws Exception{
		return new DataSourceTransactionManager(dataSource());
	}
	

}

service,发生一次异常

@Service
public class UserService {
	
	@Autowired
	private UserDao userDao;
	
	@Transactional
	public void insertUser(){
		userDao.insert();
		//otherDao.other();xxx
		System.out.println("插入完成...");
		int i = 10/0;
	}

}

dao ,保存一条数据

@Repository
public class UserDao {
	
	@Autowired
	private JdbcTemplate jdbcTemplate;
	public void insert(){
		String sql = "INSERT INTO `user_info`(`name`,sex) VALUES(?,?)";
		String username = UUID.randomUUID().toString().substring(0, 5);
		jdbcTemplate.update(sql, username,1);
		
	}

}
单元测试
@Test
	public void test01(){
		AnnotationConfigApplicationContext applicationContext = 
				new AnnotationConfigApplicationContext(TxConfig.class);
	
		UserService userService = applicationContext.getBean(UserService.class);
		
		userService.insertUser();
		applicationContext.close();
	}

结果sql执行新增过后, 数据库数据没有变化,因为异常导致事务回滚。

spring 声明式事务rollbackOnly_bc

二.@EnableTransactionManagement

和AOP 的@Enable注解一样,看看它给容器注入了什么?

spring 声明式事务rollbackOnly_bc_02

TransactionManagementConfigurationSelector,实现了ImportSelector接口,就看 selectImports方法的返回结果是什么,就会往容器中注入什么组件。

根据adviceMode的值去注入不同的组件。

spring 声明式事务rollbackOnly_bc_03

adviceMode的值在 EnableTransactionManagement 中 默认为 AdviceMode.PROXY,所以会注入 AutoProxyRegistrar 和ProxyTransactionManagementConfiguration。

proxyTargetClass ,默认值为false,一会用到。

spring 声明式事务rollbackOnly_bc_04

1.AutoProxyRegistrar

实现了 ImportBeanDefinitionRegistrar接口,可以用 BeanDefinitionRegistry 自定义往容器中注册组件。

spring 声明式事务rollbackOnly_Spring事务_05

可以打断点看看:

1.importingClassMetadata.getAnnotationTypes(); 得到一些标注的注解,并遍历

2.AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);得到注解的属性

3.如果注解的mode属性值不为空,且属性proxyTargetClass不为空,且...符合后面的条件,最终会执行AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);

而proxyTargetClass ,默认值为false,forceAutoProxy不会执行。

spring 声明式事务rollbackOnly_bc_06

 会往容器中注入InfrastructureAdvisorAutoProxyCreator 实例

spring 声明式事务rollbackOnly_Spring事务_07

InfrastructureAdvisorAutoProxyCreator看继承关系,和AOP的AnnotationAwareAspectJAutoProxyCreator很像,是个BeanPostProcessor。

spring 声明式事务rollbackOnly_事务管理_08

spring 声明式事务rollbackOnly_Source_09

没有找到InfrastructureAdvisorAutoProxyCreator重写postProcessAfterInitialization等后置处理的方法,说明它的功能和AbstractAutoProxyCreator一样,如下和AOP一样。

spring 声明式事务rollbackOnly_Spring事务_10

打断点,查看userService的初始化(事务注解写在了userService上),

会发现它有个增强器,最终会返回userService的代理对象。

跟AOP一样,利用代理、增强器对原方法加强。

spring 声明式事务rollbackOnly_事务管理_11

2.ProxyTransactionManagementConfiguration

给容器注入BeanFactoryTransactionAttributeSourceAdvisor,TransactionAttributeSource(解析事务注解的属性),

TransactionInterceptor(方法拦截器)

spring 声明式事务rollbackOnly_事务管理_12

 

TransactionInterceptor实现了MethodInterceptor,是个方法拦截器,在给userservice创建代理后,调用userService的方法时,会先执行它的invoke方法。

在单元测试调用userService保存时,打断点,看看流程。

spring 声明式事务rollbackOnly_Source_13

进入断点,和AOP一样,进入了CglibAopProxy的intercept方法。

spring 声明式事务rollbackOnly_bc_14

得到方法连接器链chain中有一个元素,就是TransactionInterceptor

spring 声明式事务rollbackOnly_Spring事务_15

最后构造 CglibMethodInvocation 执行proceed方法。

spring 声明式事务rollbackOnly_bc_16

执行proceed方法,断点进入ReflectiveMethodInvocation的proceed

spring 声明式事务rollbackOnly_事务管理_17

再进入断点,就来到了TransactionInterceptor 的invoke

spring 声明式事务rollbackOnly_事务管理_18

invokeWithinTransaction方法:根据方法名来看看

1)、先获取事务相关的属性 getTransactionAttribute

spring 声明式事务rollbackOnly_Spring事务_19

  2)、再获取PlatformTransactionManager,如果事先没有添加指定任何transactionmanger,最终会从容器中按照类型获取一个PlatformTransactionManager;

3)、事务执行

    创建事务(createTransactionIfNecessary)

              --->执行目标方法(invocation.proceedWithInvocation())

                  ----->如果异常,获取到事务管理器,利用事务管理回滚操作(completeTransactionAfterThrowing(txInfo, ex));                   ----->如果正常,利用事务管理器,提交事务(commitTransactionAfterReturning(txInfo))

spring 声明式事务rollbackOnly_事务管理_20

 

我进入 createTransactionIfNecessary 创建事务的方法找了一圈,发现没有用jdbc发送"begin"语句,而是使用Connection.setAutoCommit(false),把连接对象设置为非自动提交,如果是新事务就这样设置为非自动提交,其他情况有其他处理,是配置的DataSourceTransactionManager操作的。

当需要回滚最后使用的方法是 Connection.rollback,提交事务是Connection.commit。

总结:

@EnableTransactionManagement

在容器中引入了 一个BeanPostProcessor,跟aop一样对注解@Transication的类进行增强

引入一个增强器,TransactionInterceptor,注解了@Transication的方法会用TransactionInterceptor增强

TransactionInterceptor

  • invokeWithinTransaction方法,明显的try catch代码块,使用我们配置的事务管理器(不配置有平台默认的) 进行开启事务、执行目标方法、异常回滚事务、正常提交事务
  • 如果是新事务,使用Connection.setAutoCommit(false)就表示开启了
  • 事务管理器最终调用的是  Connection.rollback回滚,Connection.commit。提交