背景
spring在使用事务的时候会出现事务失效的情况。这里了解spring中事务原理,以及事务失效的原理和解决方案。
原因
spring中事务是基于AOP的,如果不是代理对象执行的话就不会有事务。
比如,加上 @Transactional 的事务方法,是被包裹起来的。
public class UserServiceProxy extends UserService {
UserService target;
public void test() {
// 切面逻辑 spring transaction
// 有 @Transactional 则开启事务
target.test();
// 1. 事务管理器新建一个数据库连接 conn
// 2. 数据库连接的 autocommit 设置位 false conn.autocommit = false;
// jdbcTemplate 会获取到前面建立的数据库连接
// 执行SQL
// 调用连接到 commit 方法提交事务 conn.commit();
// 如果失败,就调用连接的 rollback 进行回滚
}
}
@Transactional
public void testTransactionManager() {
jdbcTemplate.execute("INSERT INTO `demo_db`.`x_sys_tb_user`(`user_id`, `user_name`) VALUES ('1', '1');");
subA();
}
// propagation 传播
// 设置传播类型
@Transactional(propagation = Propagation.NEVER)
public void subA() {
jdbcTemplate.execute("INSERT INTO `demo_db`.`x_sys_tb_user`(`user_id`, `user_name`) VALUES ('2', '2');");
}
在执行 testTransactionManager() 的时候 ,subA();是 target即普通对象执行的。
事务生效解决办法
- 拆分,把失效的事务拆分出去。新建一个对象把失效的事务方法放到这个对象中,然后注入这对象,
- 自己注入自己(注:在 spring 中也算是循环依赖,但是 spring 帮我们解决了)
- AopContext.currentProxy() 获取当前的代理对象,然后用代理对象调用失效的事务(注:这种方法可能可读性差一点)