Spring事务失效,常见的情况有哪些?

简介: 本文总结了Spring事务失效的7种常见情况,包括未启用事务管理功能、方法非public类型、数据源未配置事务管理器、自身调用问题、异常类型错误、异常被吞以及业务和事务代码不在同一线程中。同时提供了两种快速定位事务相关Bug的方法:通过查看日志(设置为debug模式)或调试代码(在TransactionInterceptor的invoke方法中设置断点)。文章帮助开发者更好地理解和解决Spring事务中的问题。

1、事务失效的7种情况

  1. 未启用spring事务管理功能
  2. 方法不是public类型的
  3. 数据源未配置事务管理器
  4. 自身调用问题
  5. 异常类型错误
  6. 异常被吞了
  7. 业务和spring事务代码必须在一个线程中

1.1、未启用spring事务管理功能

@EnableTransactionManagement 注解用来启用spring事务自动管理事务的功能,这个注解千万不要忘记写了。

1.2、方法不是public类型的

@Transaction 可以用在类上、接口上、public方法上,如果将@Trasaction用在了非public方法上,事务将无效。

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

spring是通过事务管理器了来管理事务的,一定不要忘记配置事务管理器了,要注意为每个数据源配置一个事务管理器:

typescript

代码解读

复制代码

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

1.4、自身调用问题

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

看下面代码,大家思考一个问题:当外部直接调用m1的时候,m2方法的事务会生效么?

typescript

代码解读

复制代码

@Component
public class UserService {    
public void m1(){       
 this.m2();    
}        
@Transactional    
public void m2(){       
 //执行db操作   
 }
}

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

typescript

代码解读

复制代码

@Component
public class UserService {   
 @Autowired //@1   
 private UserService userService;    
public void m1() {        
this.userService.m2();    
}    
@Transactional    
public void m2() {      
  //执行db操作   
 }
}

重点:必须通过代理对象访问方法,事务才会生效。

1.5、异常类型错误

spring事务回滚的机制:对业务方法进行try catch,当捕获到有指定的异常时,spring自动对事务进行回滚,那么问题来了,哪些异常spring会回滚事务呢?

并不是任何异常情况下,spring都会回滚事务,默认情况下,RuntimeException和Error的情况下,spring事务才会回滚。

也可以自定义回滚的异常类型:

ini

代码解读

复制代码

@Transactional(rollbackFor = {异常类型列表})

1.6、异常被吞了

当业务方法抛出异常,spring感知到异常的时候,才会做事务回滚的操作,若方法内部将异常给吞了,那么事务无法感知到异常了,事务就不会回滚了。

如下代码,事务操作2发生了异常,但是被捕获了,此时事务并不会被回滚

typescript

代码解读

复制代码

@Transactional
public void m1(){    
事务操作1    
try{       
 事务操作2,内部抛出了异常    
}
catch(Exception e){            
}
}

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

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

typescript

代码解读

复制代码

@Transactional
public void m1() {    
new Thread() {       
 一系列事务操作    
}.start();
}

2、如何快速定位事务相关bug?

2种方式

方式1:看日志

如果你使用了logback或者log4j来输出日志,可以修改一下日志级别为debug模式,可以看到事务的详细执行日志,帮助你定位错误

方式2:调试代码

如果你对源码比较了解,那么你会知道被spring管理事务的业务方法,执行的时候都会被TransactionInterceptor拦截器拦截,会进入到它的invoke方法中,咱们可以在invoke方法中设置一些断点,可以看到详细的执行过程,排错也就比较容易了。


转载来源:https://juejin.cn/post/6916856740965580813

相关文章
|
Java
SpringBoot 内部方法调用,事务不起作用的原因及解决办法
在做业务开发时,遇到了一个事务不起作用的问题。大概流程是这样的,方法内部的定时任务调用了一个带事务的方法,失败后事务没有回滚。查阅资料后,问题得到解决,记录下来分享给大家。
1018 4
|
5月前
|
缓存 Java Spring
详细解析Spring如何解决循环依赖问题
详细解析 Spring 循环依赖原理,从三级缓存、核心源码到完整流程一步步讲解,带你彻底搞懂 Spring 如何解决 Bean 循环依赖及 AOP 代理场景下的实现细节。
702 2
|
11月前
|
SQL Java 关系型数据库
Spring事务传播机制:7种姿势教你玩转"事务接力赛"
事务传播机制是Spring框架中用于管理事务行为的重要概念,它决定了在方法调用时事务如何传递与执行。通过7种传播行为,开发者可以灵活控制事务边界,适应不同业务场景。例如:REQUIRED默认加入或新建事务,REQUIRES_NEW独立开启新事务,NESTED支持嵌套回滚等。合理使用传播机制不仅能保障数据一致性,还能提升系统性能与健壮性。掌握这“七种人格”,才能在复杂业务中游刃有余。
|
人工智能 Java 数据库连接
Spring事务失效场景
本文深入探讨了Spring框架中事务管理可能失效的几种常见场景及解决方案,包括事务方法访问级别不当、方法内部自调用、错误的异常处理、事务管理器或数据源配置错误、数据库不支持事务以及不合理的事务传播行为或隔离级别。通过合理配置和正确使用`@Transactional`注解,开发者可以有效避免这些问题,确保应用的数据一致性和完整性。
1159 10
|
XML SQL Java
Spring 事务失效的六种情况
Spring 事务失效的六种情况
1547 0
|
前端开发 Java 应用服务中间件
SpringBoot-Run启动流程
探索Spring Boot启动流程,从加载配置、创建应用上下文、自动配置到启动内嵌服务器。启动类是入口点,`@SpringBootApplication`标记启动,`SpringApplication.run`启动应用。自动配置基于条件注解配置Bean,应用上下文由`SpringApplication`创建并刷新。内嵌服务器如Tomcat随应用启动,简化部署。理解此流程有助于深入掌握Spring Boot。
850 2
|
开发框架 Java 开发者
Spring Boot中的自动装配原理
Spring Boot中的自动装配原理
3924 1
|
消息中间件 存储 监控
七种常见分布式事务详解(2PC、3PC、TCC、Saga、本地事务表、MQ事务消息、最大努力通知)
七种常见分布式事务详解(2PC、3PC、TCC、Saga、本地事务表、MQ事务消息、最大努力通知)
7027 0
|
SQL druid Java
线程池相关故障问题之Druid数据库连接池中,为何需要设置TransactionTimeout
线程池相关故障问题之Druid数据库连接池中,为何需要设置TransactionTimeout
1074 0
|
存储 Java
HashMap之链表转红黑树(树化 )-treefyBin方法源码解读(所有涉及到的方法均有详细解读,欢迎指正)
本文详细解析了Java HashMap中链表转红黑树的机制,包括树化条件(链表长度达8且数组长度≥64)及转换流程,确保高效处理大量数据。
1241 1

热门文章

最新文章