@Transactional与synchronized

3 篇文章 0 订阅

错误代码:

@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,事务将不会发生回滚:

  1. TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  2. TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  3. 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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值