求求你,别再乱用@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,哈哈哈,比较码字不容易呀,你的支持就是小编连载的动力,求三连求三连求三连🥹 (❁´◡❁)(❁´◡
❁)
🖊️最后总结
🖲要熟练掌握技巧,一定多多坚持练习:骐骥一跃,不能十步;驽马十驾,功在不舍。