java事务不生效场景_导致spring事务失效的几种场景

  • Post author:
  • Post category:java


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是通过事务管理器来管理事务的,一定要配置事务管理器

@BeanpublicPlatformTransactionManager transactionManager(DataSource dataSource) {

return newDataSourceTransactionManager(dataSource);}

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

1.4自身调用问题

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

@Servicepublic classTransactionDemoService {

public voidm1(){

this.m2();;}

@Transactional(rollbackFor= Exception.class)

public voidm2(){

//db操作}

}

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

@Servicepublic classTransactionDemoService {

@AutowiredprivateTransactionDemoService self;

public voidm1(){

self.m2();;}

@Transactional(rollbackFor= Exception.class)

public voidm2(){

//db操作}

}

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

@Servicepublic classTransactionDemoService {

public voidm1(){

((TransactionDemoService)AopContext.currentProxy()).m2();}

@Transactional(rollbackFor= Exception.class)

public voidm2(){

//db操作}

}

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

1.5异常类型错误

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

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

@Transactional(rollbackFor= AccessException.class)

public voidm2(){

//db操作}

1.6异常被捕获

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

@Transactional(rollbackFor= Exception.class)

public voidm2(){

try{

//db操作}catch(Exception e){

logger.error(“方法执行出现异常”,e);}

}

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

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

@Transactional(rollbackFor= Exception.class)

public voidm1() {

newThread() {//db操作}.start();}



版权声明:本文为weixin_42526068原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。