求求你,别再乱用@Transactional了

求求你,别再乱用@Transactional了

🔊先看个问题

你觉得test2方法执行后 user1表有几条数据?

📕情况1

情况1结果

三条记录都保存成功了

🖥️情况2

catch中throw出异常

情况2结果

没有数据

📜 情况三

去掉test2中的@transactional 与catch中的throw异常

情况3结果

三条都保存了

📘情况4

使用依赖注入方式调用all

情况4结果

两条数据 id为3,4的出现异常 回滚了,其他正常保存

铁子们,怎么样,此时你的表情是这样的

还是这样的

是不是脑瓜子嗡嗡的😂,不要慌,这就给你们解密哈

🔖先说结论

情况1结果

只有一个事务,就是test2上的

情况2结果

只有一个事务,就是test2上的,i=1的记录报错了,导致事务最终回滚,三条记录都不保存

情况3结果

根本没有事务!!!!!

???为什么?why?what 发科??😳

-》因为all方法是this调用;为什么this调用就不会用到事务呢,不要慌,后面会详细解释的哈

情况4结果

存在三个独立事务,都是all方法发起的,因为调用all方法是通过注入的方式调用,所以会产生事务

兄弟们,脑壳不要打铁,忘掉刚刚的所有,无招胜有招,看一看下面的魔术揭秘,看完你就会评论区留言,小编这啥小儿科问题,太简单了,so easy,哈哈哈哈😄

1、首先讲解下spring中是怎么处理事务的

spring声明式事务是通过事务拦截器TransactionInterceptor拦截目标方法,来实现事务管理的功能的,事务管理器处理过程大致如下:

java 复制代码
1、获取事务管理器
2、通过事务管理器开启事务
try{
    3、调用业务方法执行db操作
    4、提交事务
}catch(RuntimeException | Error){
    5、回滚事务
}

2、何时事务会回滚?

默认情况下,目标方法抛出RuntimeException或者Error的时候,事务会被回滚。

3、Spring事务管理器中的Connection和业务中操作db的Connection如何使用同一个的?

以DataSourceTransactionManager为事务管理器,操作db使用JdbcTemplate来说明一下。

创建DataSourceTransactionManager和JdbcTemplate的时候都需要指定dataSource,需要将他俩的dataSource指定为同一个对象。

当事务管理器开启事务的时候,会通过dataSource.getConnection()方法获取一个db连接connection,然后会将dataSource->connection丢到一个Map中,然后将map放到ThreadLocal中。

当JdbcTemplate执行sql的时候,以JdbcTemplate.dataSource去上面的ThreadLocal中查找,是否有可用的连接,如果有,就直接拿来用了,否则调用JdbcTemplate.dataSource.getConnection()方法获取一个连接来用。

所以spring中可以确保事务管理器中的Connection和JdbcTemplate中操作db的Connection是同一个,这样才能确保spring可以控制事务。

所以说,要想事务被回滚,必须让事务识别到异常,那个地方开启了事务,那个地方则需要识别到异常,没识别到则不会回滚,对比看下情况1和情况2,此时是不是比较清晰

再看情况3和情况4

因为spring声明式事务是通过事务拦截器TransactionInterceptor拦截目标方法,来实现事务管理的功能的所以通过this.all去调用的方法不会经过事务拦截器,也就没有事务啦

要想让事务生效,则必须通过注入的方式去调用❗️❗️❗️❗️❗️

此时再看下情况3,是不是了解了情况三为啥没事务啦

再看情况4,为啥他会开启三个事务呢

那是因为Spring事务中一共有7种传播行为,默认的则是REQUIRED****

📚7种传播行为

Propagation是个枚举,有7种值,如下:

事务传播行为类型 说明
REQUIRED 如果当前事务管理器中没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择,是默认的传播行为。
SUPPORTS 支持当前事务,如果当前事务管理器中没有事务,就以非事务方式执行。
MANDATORY 使用当前的事务,如果当前事务管理器中没有事务,就抛出异常。
REQUIRES_NEW 新建事务,如果当前事务管理器中存在事务,把当前事务挂起,然后会新建一个事务。
NOT_SUPPORTED 以非事务方式执行操作,如果当前事务管理器中存在事务,就把当前事务挂起。
NEVER 以非事务方式执行,如果当前事务管理器中存在事务,则抛出异常。
NESTED 如果当前事务管理器中存在事务,则在嵌套事务内执行;如果当前事务管理器中没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

所以调用all的时候由于test2中没有事务,all则会自己新建一个事务啦,for循环了三次,则会新建三个事务呀,大家是不是都看明白了呢

看懂了建议给小编评论区来一波666,哈哈哈,比较码字不容易呀,你的支持就是小编连载的动力,求三连求三连求三连🥹 (❁´◡❁)(❁´◡❁)

🖊️最后总结

🖲要熟练掌握技巧,一定多多坚持练习:骐骥一跃,不能十步;驽马十驾,功在不舍

相关推荐
monkey_meng16 分钟前
【Rust Crate之Actix Web(一)】
开发语言·后端·rust
2401_8570262338 分钟前
SpringBoot环境下的共享汽车管理策略
spring boot·后端·汽车
2401_857622661 小时前
共享汽车管理:SpringBoot技术实现与优化
spring boot·后端·汽车
夜色呦1 小时前
SpringBoot助力的共享汽车业务优化系统
spring boot·后端·汽车
代码小鑫1 小时前
A15基于Spring Boot的宠物爱心组织管理系统的设计与实现
java·开发语言·spring boot·后端·毕业设计·宠物
2401_871290582 小时前
Scala 中的Set
开发语言·后端·scala
Afanda…2 小时前
Git超详细教程
运维·后端·gitee
黄俊懿3 小时前
【架构师从入门到进阶】第一章:架构设计基础——第五节:架构演进(缓存到微服务)
分布式·后端·缓存·微服务·架构·系统架构·架构设计
一位资深码农5 小时前
面试题分享11月7日
后端
许野平13 小时前
Rust:启动与关闭线程
开发语言·后端·rust·线程·启动·关闭