当前位置:首页 » 操作系统 » spring数据库事物

spring数据库事物

发布时间: 2023-07-03 22:07:21

1. “Spring”事务失效的场景

1.数据库引擎不支持事务

Spring 事务生效的前提是所连接的数据库要支持事务,如果底层的数据库引擎都不支持事务,则Spring的事务肯定会失效。

例如: Mysql 用的不是 InnoDB 引擎,而是用的 MyISAM 存储引擎。

2.事务方法未被 Spring 容器管理

如果事务方法所在的类没有加载到 Spring IOC 容器中,也就是说,事务方法所在的类没有被 Spring 容器管理,则Spring事务会失效。

例如:你的方法所在类没有加@Component或者@Service注解。

3.方法没有被 public 修饰

如果事务所在的方法没有被 public 修饰,此时 Spring 的事务也会失效。

4.同一类中方法之间直接的调用

例如:如果同一个类中有两个岁毕方法分别为 A 和 B,方法 A 没有添加事务注解,而方法 B 添加了 @Transactional 事务注解,此时方法 A 直接调用方法 B,则方法 B 的事务会失效。

5.未配置事务管理器

如果在项目中没有配置 Spring 的事务管理器,即使使用了 Spring 的事务管理功能,Spring 的事务也不会生效。

例如:对于 SpringBoot 项目来说,导入了 mybatis 的 starter 依赖后,SpringBoot 会自动注入DataSourceTransactionManager 事务管理器,这样我们就可以直接用 @Transactional 注解使用事务了。

6.事枯行务传播类型不支持事务

如果方法的事务传播类型为不支持事务没雀哗的传播类型,则该方法的事务在 Spring 中会失效。

例如: A 方法的事务传播类型为 NOT_SUPPORTED,不支持事务,此时用带事务的方法 B 去调用 A 方法,则 A 方法的事务失效。

7.进行异常捕捉却没有抛出

比如对某一个新增数据代码段进行 try catch 异常,而 catch 里没有向外抛出异常,此时 spring 事务无法回滚。

8.错误的标注异常类型

如果在 @Transactional 注解中标注的异常类型不是我们抛出的异常类型,则Spring事务的回滚会失效。

例如: Spring 中默认回滚的异常类型为 RuntimeException,如果此时你抛出的异常是 Exception,那么Spring 事务中无法捕获到 Exception 异常,则事务回滚会失效。

9.开启多线程

开启一个线程去执行数据库操作,多线程内的方法将不被 spring 事务控制。

例如:一个带事务的方法 A 中开启线程去执行同类中的一个 insert 方法,即使这个操作失败了,也不会回滚 A 中的其他数据库操作。

注意:如果把 insert 方法提出到一个新的类中,加入事务注解,就能成功的把 insert 方法加入到 spring 事务管理中。但是使用多线程事务的情况下,如果想进行回滚,比较麻烦,因为我们感知不到线程中方法执行的异常。

2. spring事务失效的几种场景以及原因

spring事务失效场景可能大家在很多文章都看过了,所以今天就水一篇,看大家能不能收获一些不一样的东西。直接进入主题

失效原因: spring事务生效的前提是,service必须是一个bean对象
解决方案: 将service注入spring

失效原因: spring默认只会回滚非检查异常和error异常
解决方案: 配置rollbackFor

失效原因: spring事务只有捕捉到了业务抛出去的异常,才能进行后续的处理,如果业务自己捕获了异常,则事务无法感知
解决方案:
1、将异常原样抛出;
2、设置TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

失效原因: spring事务切面的优先级顺序最低,但如果自定义的切面优先级和他一样,且自定义的切面没有正确处理异常,则会同业务自己捕获异常的那种场景一样
解决郑含方案:
1、在切面中将异常原样抛出;
2、在切面中设置TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

失效原因: spring事务默认生效的方法权限都必须为public

解决方案:
1、将方法改为public;
2、修改TansactionAttributeSource,将publicMethodsOnly改为false【这个从源码跟踪得出结论】
3、开启 AspectJ 代理模式【从spring文档得出结论】

具体步骤:

1、在pom引入aspectjrt坐标以及相应插件

2、在启动类上加上如下配置

注: 如果是在idea上运行,则需做如下配置


4、直接用TransactionTemplate

示例:

失效原因: 子容器扫描范围过大,将未加事务配置的serivce扫描进来

解决方案:
1、父子容器个扫个的范围;
2、不用父子容器,所有bean都交给同一容器管理

注: 因为示例是使用springboot,而springboot启动默认没有父子容器,只有一个容器,因此就该场景就演示示例了

失效原因: 因为spring事务亩轿是用动态代理实现,因此如果方法使用了final修饰,则代理类无法对目标方法进行重写,植入事务功能

解决方案:
1、方法不要用final修饰

失效原因: 原因和final一样

解决方案:
1、方法不要用static修饰

失效原因: 本类方法不经过代理,无法进行增强

解决方案:
1、注入自己来调用;
2、使用@EnableAspectJAutoProxy(exposeProxy = true) + AopContext.currentProxy()

失效原因: 因为spring的事务是通过数据库连接来实现,而数据库连接spring是放在threadLocal里面。同一个事务,只能用同一个数据库连接。而多线程场景下,拿到的数据库连接是不一样的,即是属于不同事务

失效原因: 使用的传播特性不支持事迅丛肆务

失效原因: 使用了不支持事务的存储引擎。比如mysql中的MyISAM

注: 因为springboot,他默认已经开启事务管理器。org.springframework.boot.autoconfigure.jdbc.。因此示例略过

失效原因: 当代理类的实例化早于AbstractAutoProxyCreator后置处理器,就无法被AbstractAutoProxyCreator后置处理器增强

本文列举了14种spring事务失效的场景,其实这14种里面有很多都是归根结底都是属于同一类问题引起,比如因为动态代理原因、方法限定符原因、异常类型原因等

https://github.com/lyb-geek/springboot-learning/tree/master/springboot-transaction-invalid-case

热点内容
配置试剂的瓶子如何灭菌 发布:2025-03-19 11:07:16 浏览:599
c语言编译生成文件 发布:2025-03-19 11:06:00 浏览:890
androidlistview列表 发布:2025-03-19 10:58:23 浏览:611
解压费是什么合同 发布:2025-03-19 10:53:32 浏览:39
java经典程序100例 发布:2025-03-19 10:52:46 浏览:524
php保留小数点后两位 发布:2025-03-19 10:47:47 浏览:428
c语言long是什么意思 发布:2025-03-19 10:47:10 浏览:899
离散数学编程 发布:2025-03-19 10:46:23 浏览:456
轿车买哪个配置的 发布:2025-03-19 10:46:22 浏览:844
linux打包目录 发布:2025-03-19 10:39:02 浏览:208