事务遇到异常时的几点注意事项

1、事务不是遇到所有异常都会回滚,默认只有遇到遇到运行异常(RuntimeException)和程序错误(Error)才会回滚,非运行异常必须在

@Transactional 注解中使用 rollbackFor 属性来指定异常,比如:@Transactional(rollbackFor = Exception.class),才会回滚。

2、我们在处理异常时,有两种方式,要么抛出去,让上一层来捕获处理;要么把异常 try...catch 掉,在异常出现的地方给处理掉。就因为有这个 try...catch,所以导致异常被 “吃” 掉,事务无法回滚。遇到异常直接往上抛,给上一层来处理即可,千万不要在事务中把异常自己 ”吃“ 掉

3、事务是有范围的

@Service
public class UserServiceImpl implements UserService {

   @Resource
   private UserMapper userMapper;

   @Override
   @Transactional(rollbackFor = Exception.class)
   public synchronized void insertUser(User user) {
       // 实际中的具体业务……
       userMapper.insertUser(user);
   }
}

如上,同个事务中方法添加了synchronized锁,避免针对同个用户进行两步相同添加操作,但实际并发测试会出现添加两次操作,原因是事务的范围比锁的范围大,也就是说,在加锁的那部分代码执行完之后,锁释放掉了,但是事务还没结束,就在此时另一个线程进来了,事务没结束的话,第二个线程进来时,数据库的状态和第一个线程刚进来是一样的。即由于mysql Innodb引擎的默认隔离级别是可重复读(在同一个事务里,SELECT的结果是事务开始时时间点的状态),线程二事务开始的时候,线程一还没提交完成,导致读取的数据还没更新。第二个线程也做了插入动作,导致了脏数据。

处理方法:第一,把事务去掉即可(不推荐);第二,在调用该 service 的地方加锁,保证锁的范围比事务的范围大即可。

 

转载自:https://mp.weixin.qq.com/s/YKm2Ud5MfjpHrRjEUjSrpQ

 

 

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值