sping事务生效与失效问题分析

一般我们使用@Transactional注解设置事务

  1. @Transactional修饰在方法上事务生效
 @Transactional
    public void saveUser(User user) {
        userRespository.save(user);
    }
  1. 方法一有事务,调用自己类或其他类的无事务方法,事务生效
 @Transactional
    public void saveUser(User user) {
        test(user);
    }

    private User test(User user) {
        User user1 = userRespository.save(user);
        int i = 1/0;
        return user1;
    }
  1. 方法一无事务,调用自己类有事务方法,事务失效
	public void saveUser(User user) {
        test(user);
    }

    @Transactional
    public User test(User user) {
        User user1 = userRespository.save(user);
        int i = 1/0;
        return user1;
    }

为什么会失效呢?:其实原因很简单,Spring在扫描Bean的时候会自动为标注了@Transactional注解的类生成一个代理类(proxy),当有注解的方法被调用的时候,实际上是代理类调用的,代理类在调用之前会开启事务,执行事务的操作,但是同类中的方法互相调用,相当于this.B(),此时的B方法并非是代理类调用,而是直接通过原有的Bean直接调用,所以注解会失效。

解决方案参考:同类方法调用事务失效问题解决

4.内部使用了try catch,吃掉异常,导致事务不生效。 这是时候推荐使用手动回滚事务

    public User test(User user) {
        try {
            //开启事务
//            DefaultTransactionDefinition df = new DefaultTransactionDefinition();
//            df.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
//            TransactionStatus transactionStatus = mysqlTransactionManager.getTransaction(df);

            User user1 = userRespository.save(user);
            int i = 1/0;
            //提交事务
           // mysqlTransactionManager.commit(transactionStatus);
        }catch (Exception e) {
            //回滚事务
            //mysqlTransactionManager.rollback(transactionStatus);
        }

    }
  1. 在事务的方法内部,另起子线程执行 db 操作,test方法导致事务失效
 @Transactional
    public void saveUser(User user) {
        new Thread(() -> {
            test(user);
        }).start();
    }

数据库引擎采用的是MyISAM,MyISAM不支持事务,InnoDB支持事务

  1. Spring的事务管理默认只对出现运行期异常(java.lang.RuntimeException及其子类)进行回滚,业务自定义的异常不支持回滚

解决办法就是:@Transactional(rollbackFor = Exception.class),且在方法中throws Exception

  1. @Transactional修饰的方法必须是public权限的,否则也会事务失效。

  2. 方法一有事务,调用方法二也有事务。事务生效

 @Transactional
    public void saveUser(User user) {
        test(user);
    }

    @Transactional
    public User test(User user) {
        User user1 = userRespository.save(user);
        int i = 1/0;
        return user1;
    }

@Transactional注解的默认传播行为为Propagation.REQUIRED

二、事务传播行为

事务传播行为类型	说明
PROPAGATION_REQUIRED	如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
PROPAGATION_SUPPORTS	支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY	使用当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW	新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED	以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER	以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED	如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

PROPAGATION_SUPPORTS、PROPAGATION_NEVER 事务都会引起事务失效。 比如方法A没有事务,调用方法B有事务,但是PROPAGATION_SUPPORTS类型的,就会导致事务失效。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值