Spring Boot事务配置

Spring Boot事务配置管理

事务相关

​事务的作用就是为保证用户的每一个操作都是可靠的,事务中的每一步操作都必须成功执行,只要有发生异常就回退到事务开始未进行操作的状态。这很好理解,转账、购票等等,必须整个事件流程全部执行完才能人为该事件执行成功,不能转钱转到一半,系统死了,转账人钱没了,收款人钱还没到。

Spring Boot事务配置

  1. 依赖导入

    ​ 导入依赖之后会自动注入DataSourceTransactionManager 无需其他配置就可使用@Transactional注解进行事务的使用l。

  2. 简单测试(略)

  3. 常见问题:

    1. 异常未被捕获到的情况

      示例代码:

      @Service
      public class UserServiceImpl implements UserService {
          @Resource
          private UserMapper userMapper;
          
          @Override
          @Transactional
          public void isertUser2(User user) throws Exception {
              // 插入用户信息
              userMapper.insertUser(user);
              // 手动抛出异常
              throw new SQLException("数据库异常");
          }
      }
      

      上面这个代码,其实并没有什么问题,手动抛出一个 SQLException 来模拟实际中操作数据库
      发生的异常,在这个方法中,既然抛出了异常,那么事务应该回滚,实际却不如此。

      因为 Spring Boot 默认的事务规则是遇到运行异常(RuntimeException)和程序
      错误(Error)才会回滚。比如上面我们的例子中抛出的 RuntimeException 就没有问题,但是抛出
      SQLException 就无法回滚了。针对非运行时异常,如果要进行事务回滚的话,可以在
      @Transactional 注解中使用 rollbackFor 属性来指定异常,比如 @Transactional(rollbackFor = Exception.class) ,这样就没有问题了,所以在实际项目中,一定要指定异常。

    2. 异常被 ”吃“ 掉的情况

      ​ 在处理异常时,有两种方式,要么抛出去,让上一层来捕获处理;要么把异常 try catch 掉,在异常出现的地方给处理掉。就因为有这种 try...catch,所以导致异常被 ”吃“ 掉,事务无法回滚。

      解决办法:直接往上抛,给上一层来处理即可,千万不要在事务中把异常自己 ”吃“ 掉

    3. 事务的范围

      ​ 并发场景下,方法上加了@Transactional,方法内部使用synchronized关键字,该方法执行,事务启动,整个方法执行结束,事务关闭。出现问题的原因是:因为事务的作用范围比锁的范围大,也就是说,在加锁的那部分代码执行完之后,锁释放掉了,但是事务还没结束,此时另一个线程进来了,事务没结束的话,第二个线程进来时,数据库的状态和第一个线程刚进来是一样的。即由于mysql Innodb引擎的默认隔离级别是可重复读(在同一个事务里,SELECT的结果是事务开始时时间点的状态),线程二事务开始的时候,线程一还没提交完成,导致读取的数据还没更新。第二个线程也做了插入动作,导致了脏数据。

上一篇:7年*ava一次坑爹的面试经历


下一篇:spring的传播机制