SpringBoot事务失效场景

首先你要注意的是你的sql语句是不是create table等ddl语句 有:CREATE DATABASE,CREATE TABLE,ALTER TABLE ,DROP TABLE,CREATE VIEW,ALTER VIEW ,DROP VIEW 等

如果是这样的,事务是不会生效的!!!!

一.事务不生效

1.访问权限的问题

如果我们在开发过程中,把有事务的方法定义了错误的权限,就会导致事务功能出错。众所周知,spring要求被代理的方法必须是public的。说白了,在AbstrctFallbackTransactionAttributedSource类的computeTransactionAttribute方法中有个判断,如果目标不是public则TransactionAttribute返回的是空

protected TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) {
        if (this.allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
            return null;
        } else {
            Class<?> userClass = ClassUtils.getUserClass(targetClass);
            Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);
            specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
            TransactionAttribute txAttr = this.findTransactionAttribute(specificMethod);
            if (txAttr != null) {
                return txAttr;
            } else {
                txAttr = this.findTransactionAttribute(specificMethod.getDeclaringClass());
                if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
                    return txAttr;
                } else {
                    if (specificMethod != method) {
                        txAttr = this.findTransactionAttribute(method);
                        if (txAttr != null) {
                            return txAttr;
                        }

                        txAttr = this.findTransactionAttribute(method.getDeclaringClass());
                        if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
                            return txAttr;
                        }
                    }

                    return null;
                }
            }
        }
    }

2.方法被final修饰

spring事务底层使用的是aop,也就是哦通过jdk动态代理或者cglib动态代理,如果某个方法使用final修饰后,在代理类中就无法重写。

3,方法内部调用

比如在service某个事务方法中调用了另外一个事务方法。事务会失效

    
     public  void doSomeThing() {
        Random random = new Random();
        Integer s = random.nextInt(100);
        Mamber mamber = new Mamber(s, "zhangsan", "123");
        mamberMapper.saveData(mamber);
        int i =1/0;
        updateData(mamber);
    }
    @Transactional
    public void updateData(Mamber mamber){
        mamber.setName("lisi");
        mamberMapper.updateData(mamber);
    }

   是因为在调用updateData的时候,用了this对象的方法,又因为是动态代理,所以updateData不会生成事务. 

((Service)AopContext.currentProxy()).updateData(mamber);

4.没有写@Service  就是没有被Spring管理

5.多线程调用

因为不同的线程调用的是不同的数据库链接,这个数据库连接是用ThreadLocal保存的, 多个线程会有多个ThreadLocal,所以链接不同了,事务也就失效了

6.表不支持事务  比如MyISAM

7.未使用@Transactional注解

二.事务不回滚

1.错误的传播特性

spring支持7种传播特性

REQUIRED 如果当前上下文存在事务,那么加入该事务,不存在事务就创建一个事务(默认)

SUPPORTS 如果当前上下文存在事务,则支持事务加入事务,如果不存在事务,就使用非事务的方式执行

MANDATORY 如果当前上下文存在事务,否认抛出异常

NOT_SUPPORTS 如果当前上下文存在事务,则挂起当前事务,然后新的方法在没有事务的环境下执行

NEVER 如果上下文存在事务则抛出异常,否则在无事务环境上执行代码

NESTED 如果上下文存在事务,则嵌套事务执行,如果不存在事务,则新建事务

2.自己吞了异常

事务不回滚 可能是开发者在代码中手动try catch了异常

3.手动抛出别的异常

即使开发者没有手动捕获异常,但是如果抛出的异常不正确,spring事务也不会回滚

默认情况下只会回滚RuntimeException 和Error。对于普通异常不会回滚

4.自定义异常

在使用@Transactional注解生命十五是,有时候我们想自定义回滚的异常,spring也是支持的,可以通过设置rollbackFor参数来完成这个功能

rollBack默认值是UncheckdException包括RuntimeException和Error

所以建议设置成Exception或者Throwable.

5.嵌套事务回滚多了

还是上面事务方法调用了另一个事务方法,但是我不想让第一个事务方法中回滚,那么只需要在另一个事务方法中手动捕获异常就可以了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值