
疑问,确实像往常一样在service上添加了注解 @Transactional,为什么查询时还是发现有数据不一致的情况,想想肯定是事务没起作用,出现异常的时候数据没有回滚。于是就对相关代码进行了一番测试,结果发现一下踩进了两个坑,确实是事务未回滚导致的数据不一致。下面总结一下经验教训。
下面先总结一下Spring的事务管理方式,spring支持两种事务管理的操作方式,编程式的和声明式的(xml或者注解)。
编程式的事务管理(实际应用中很少使用)
通过使用TransactionTemplate 手动管理事务
声明式的事务管理(开发中推荐使用(代码侵入最少))
Spring的声明式事务是通过AOP实现的
总结一下导致事务不回滚的两个原因,一是Service类内部方法调用,二是try…catch异常。
大概就是 Service 中有一个方法 A,会内部调用方法 B, 方法 A 没有事务管理,方法 B 采用了声明式事务,通过在方法上声明 Transactional 的注解来做事务管理。示例代码如下:
@Service
public class RabbitServiceImpl implements RabbitService {
@Autowired
private RabbitDao rabbitDao;
@Autowired
private TortoiseDao tortoiseDao;
@Override
public Rabbit methodA(String name){
return methodB(name);
}
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
public boolean methodB(String name){
rabbitDao.insertRabbit(name);
tortoiseDao.insertTortoise(name);
return true;
}
}
单元测试代码如下:
public class RabbitServiceImplTest {
@Autowired
private RabbitService rabbitService;
// 事务未开启
@Test
public void testA(){
rabbitService.methodA("rabbit");
}
// 事务开启
@Test
public void testB(){
rabbitService.methodB("rabbit");
}
}
从上一节中可以看到,声明式事务是通通过AOP动态代理实现的,这样会产生一个代理类来做事务管理,而目标类(service)本身是不能感知代理类的存在的。
对于加了@Transactional注解的方法来说,在调用代理类的方法时,会先通过TransactionInterceptor开启事务,然后在调用目标类的方法,最后在调用结束后,TransactionInterceptor 会提交或回滚事务,大致流程如下图:

总结,在方法 A 中调用方法 B,实际上是通过“this”的引用,也就是直接调用了目标类的方法,而非通过 Spring 上下文获得的代理类,所以事务是不会开启的。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-64434-1.html
瞪眼说瞎话