Spring事务失效的场景

1.事务失效的7种情况

1)未启用spring事务管理功能

2)方法不是public类型的

3)数据源未配置事务管理器

4)自身调用问题

5)异常类型错误

6)异常被捕获

7)业务和spring事务代码必须在一个线程中

1.1未启用spring事务管理功能

@EnableTransactionManagement 注解用于启用spring事务自动管理功能

如果引入了autoconfigure,TransactionAutoConfiguration.class会自动启用事务管理功能

1.2方法不是public类型

@Transactional 注解可以用到类上、接口上和public方法上,如果是非public方法,事务将不会生效,主要是spring代理机制导致

1.3数据源未配置事务管理器

spring是通过事务管理器来管理事务的,一定要配置事务管理器

@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
}

如果引入了autoconfigure,DataSourceTransactionManagerAutoConfiguration.class会自动创建事务管理器

1.4自身调用问题

spring是通过aop的方式实现的事务管理,为每个需要事务管理的bean创建代理对象, 然后通过代理对象拦截了目标方法的执行,在方法前后添加了事务的功能,所以必须通过代理对象调用目标方法的时候,事务才会起效。

@Service
public class TransactionDemoService {

    public void m1(){
        this.m2();;
    }

    @Transactional(rollbackFor = Exception.class)
    public void m2(){
        //db操作
    }
}

以上代码中,调用m1方法,m2方法中的事务是不会生效的。因为m1中调用m2是通过this调用的,不是通过代理对象。 this.m2()不会被拦截,所以事务是无效的,如果外部直接调用通过TransactionDemoService这个bean来调用m2方法,事务是有效的,上面代码可以做一下调整,如下,在TransactionDemoService中注入了自己,此时m1中的m2事务是生效的 。

@Service
public class TransactionDemoService {

    @Autowired
    private TransactionDemoService self;

    public void m1(){
        self.m2();;
    }

    @Transactional(rollbackFor = Exception.class)
    public void m2(){
        //db操作
    }
}

或者,使用AopContext也能解决这个问题,如下:

@Service
public class TransactionDemoService {

    public void m1(){
        ((TransactionDemoService)AopContext.currentProxy()).m2();
    }

    @Transactional(rollbackFor = Exception.class)
    public void m2(){
        //db操作
    }
}

注意,当使用AopContext时, 需要使用@EnableAspectJAutoProxy(exposeProxy = true)来暴露AOP的Proxy对象才行,否则会报异常。

1.5异常类型错误

spring的事务回滚机制为,对代理的方法进行try catch 当捕获到有指定的异常时,spring自动对事务进行回滚。但是, 并不是任何异常情况下,spring都会回滚事务,默认情况下,RuntimeException和Error的情况下,spring事务才会回滚。

同时,也可以自定义回滚得异常类型:

@Transactional(rollbackFor = AccessException.class)
public void m2(){
    //db操作
}

1.6异常被捕获

当业务代码抛出异常,spring感知到异常的时候,才会进行回滚,如果在业务方法里面捕获了异常,spring无法感知到异常,就不会进行回滚,如下:

@Transactional(rollbackFor = Exception.class)
public void m2(){
    try{
        //db操作
    }catch (Exception e){
        logger.error("方法执行出现异常",e);
    }
}

1.7业务和spring事务代码必须在一个线程中

spring事务实现中使用了ThreadLocal,ThreadLocal可以实现同一个线程中数据共享,必须是同一个线程的时候,数据才可以共享,这就要求业务代码必须和spring事务的源码执行过程必须在一个线程中,才会受spring事务的控制,比如下面代码,方法内部的子线程内部执行的事务操作将不受m1方法上spring事务的控制。

@Transactional(rollbackFor = Exception.class)
public void m1() {
    new Thread() {
        //db操作
    }.start();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值