求求你,别再乱用@Transactional了

2024-01-09 14:46:40

求求你,别再乱用@Transactional了

🔊先看个问题

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

📕情况1

image-20240108105311811

情况1结果

三条记录都保存成功了

image-20240108105636368

🖥?情况2

catch中throw出异常

image-20240108105751276

情况2结果

没有数据

image-20240108105859134

📜 情况三

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

image-20240108133805659

情况3结果

三条都保存了

image-20240108110509736

img

📘情况4

使用依赖注入方式调用all

image-20240108110616422

情况4结果

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

image-20240108110726046

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

image-20240108111157423

还是这样的

img

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

🔖先说结论

情况1结果

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

image-20240108111726687

情况2结果

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

image-20240108112023947

情况3结果

根本没有事务!!!!!

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

img

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

image-20240108112204153

情况4结果

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

image-20240108112713559

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

img

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

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

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,此时是不是比较清晰

image-20240108113802796

image-20240108113842695

img

再看情况3和情况4

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

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

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

image-20240108114341872

image-20240108120418725

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

image-20240108114354448

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

📚7种传播行为

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

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

img

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

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

🖊?最后总结

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

搞笑点赞

文章来源:https://blog.csdn.net/itScholar001/article/details/135478668
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。