Spring事务及事务失效的情况

定义

逻辑上的一组操作,要么全部执行,要么全部不执行。

特性(ACID)

  1. 原子性:一组操作,要么全部执行,要么全部不执行。
  2. 一致性:执行事务前后,数据保持一致。
  3. 隔离性:各事务之间相互隔离,不会相互干扰。
  4. 持久性:一个事务提交后,对数据库中的数据改变是持久的。

事务传播行为

解决业务层方法之间相互调用的事务问题

事务传播行为
REQUIRED(默认)如果存在事务,则加入事务;
如果不存在事务,则创建事务。
REQUIRS_NEW创建一个新事物,如果事物存在,则挂起事务。
SUPPORTS如果存在事务,则加入事务;
如果不存在事务,则以非事务的方式执行。
NOT_SUPPORTED以非事务方式执行操作,如果存在事务,则挂起事务
MANDATORY如果存在事务则加入事务;
如果没有事务,则抛出异常。(必须有事务)
NEVER以非事务方式执行操作,如果存在事务,则抛出异常。(必须没事务)

事务隔离级别

点击详细介绍

事务失效及解决方案

1.未捕获异常
2. 方法为非public方法
3.方法用final、static修饰
4.this调用类内部方法
5.数据库不支持
6.多线程调用

  1. 未捕获异常

    默认情况只会回滚RuntimeException(运行时异常)和Error(错误),如果一个事务方法中发生了未捕获异常,并且异常未被处理或传播到事务边界之外,事务失效。

  2. 方法为非公开方法

    如果@Transactional注解标注在私有方法上或非public方法上,事务失效。

  3. 方法用final、static修饰

    Spring事务的实现是基于动态代理的,使用final、static修饰后,无法重写改方法,所以事务失效。

  4. 调用类内部的事务方法

    因为Spirng事务是通过代理对象来控制的,使用this直接调用,绕过了Spring的代理机制,不会应用事务设置。

    @Service
    public class UserService{
        public void save(User user){
            queryData();
            save(user);
            updateStatus(user); //this调用类内部方法
        }
        
        @Transactional
        public void updateStatus(User user){
            update(user);
        }
    }
    

    解决:

    1. 创建一个Service方法

      @Service
      public class UserService{
          @Autowired
          ServiceA service
          
          public void save(User user){
              queryData();
              save(user);
              service.updateStatus(user);
          }
          
      }
      
      
      
      @Service
      public class ServiceA{
          @Transactional
          public void updateStatus(User user){
              update(user);
          }
      }
      
    2. 注入自己

      @Service
      public class UserService{
          @Autowired
          UserService userService;
          public void save(User user){
              queryData();
              save(user);
              userService.updateStatus(user); 
          }
          
          @Transactional
          public void updateStatus(User user){
              update(user);
          }
      }
      

      自己注入自己回导致循环依赖,但是Spring内部的三级缓存机制解决了该循环依赖的问题。

    3. 通过AopContext类获取代理对象

      @Service
      public class UserService{
          public void save(User user){
              queryData();
              save(user);
              ((UserService)AopContext.currentProxy()).updateStatus(user); //获取代理对象
          }
          
          @Transactional
          public void updateStatus(User user){
              update(user);
          }
      }
      
  5. 数据库不支持事务

    比如MySql使用了MyISAM引擎,它本身是不支持事务的,在这种情况下,即使添加了@Transactional主机诶,事务也不会生效。

  6. 多线程调用

    两个事务方法不在同一个线程中,获取到的数据库连接不一样,从而是两个不同的事务。如果抛出了异常,也不会正确回滚。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值