错误代码:
@Transactional
public void demo() {
//一些操作
synchronized(this) {
//操作数据库读写
}
}
1、问 题
上述代码,@Transactional注解通过aop实现事务管理,当标注该注解的方法执行完成后才提交事务,而synchronized代码块又是在一个事务内,就会出现第一个线程释放锁后但是事务还没提交,第二个线程就进入同步代码块获取到未提交的数据库数据,造成了脏读。
2、解决方案
锁上移,扩大锁的范围,包住整个事物;
public synchronized void demo() {
handleDataBase();
}
@Transactional
public void handleDataBase() {
}
上述代码,若是在一个类里面会产生新的问题,事物失效问题,因为@Transactional事务管理是基于动态代理对象的代理逻辑实现的,如果在类内部调用类内部的事务方法,这个调用事务方法的过程并不是通过代理对象来调用的,而是直接通过this对象来调用方法,所以会有事物失效。
3、解决上述事物失效问题,有3个方案
1、将handleDataBase()方法单独写个类,通过注入新建的类调用handleDataBase();
2、自己注入自己,用自己调用方法handleDataBase();
3、通过编程式事物管理;
………………扩展知识点………………
1、@Transactiona事物失效的场景
1、@Transactiona注解应用在非public修饰的方法,而且protected、private 修饰的方法上使用 @Transactional 注解,虽然事务无效,但不会有任何报错,这就容易犯错;
2、@Transactional 注解属性 propagation 设置错误,这种失效是由于配置错误,若是错误的配置以下三种 propagation,事务将不会发生回滚:
- TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
- TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
- TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
3、@Transactional 注解属性 rollbackFor 设置错误:
rollbackFor 可以指定能够触发事务回滚的异常类型。Spring 默认抛出了未检查 unchecked 异常(继承自 RuntimeException 的异常)或者 Error 才回滚事务;其他异常不会触发回滚事务。如果在事务中抛出其他类型的异常,但却期望 Spring 能够回滚事务,就需要指定 rollbackFor 属性。
4、同一个类中方法调用,导致 @Transactional 失效;
5、异常被 catch “吃了”导致 @Transactional 失效;
参考文档:https://blog.csdn.net/li15974168626/article/details/125143602