前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring避坑指南:Spring声明式事务@Transactional避坑

Spring避坑指南:Spring声明式事务@Transactional避坑

作者头像
崔认知
发布2023-06-19 17:15:31
5900
发布2023-06-19 17:15:31
举报
文章被收录于专栏:nobodynobody



简介


Spring支持两种使用事务的方式:声明式和编程式。声明式事务是大多数程序员使用的,一个注解@Transactional走天下,由于事务的特性及事务是由aop技术来实现的,往往会碰到一些坑,使得事务失效或性能受损,甚至发生死锁现象。

事务失效的坑:AOP技术限制引起的


Spring中的事务是AOP实现的,Srping AOP使用JDK动态代理或CGLIB来创建代理对象。

默认情况下,如果需要代理的对象实现了接口,则使用JDK动态代理,否则使用CGLIB。

可以参考文档:

https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-proxying

或源码:

代码语言:javascript
复制
org.springframework.aop.framework.DefaultAopProxyFactory

由于JDK动态代理或CGLIB来创建代理技术限制,某些方法或行为不能创建代理行为或自动使用代理对象调用方法,会使得事务失效。

1、final方法添加@Transactional,事务不生效;

2、static方法添加@Transactional,事务不生效;

3、非public方法添加@Transactional,事务不生效;

可以通过class-based proxies or consider using AspectJ compile-time or load-time weaving解决。

4、同一个类的带有事务注解@Transactional的两个方法self-invocation行为,事务不生效;

jdk动态代理技术肯定失效,可以通过CGLIB技术规避。

事务的坑:Spring实现机制引起的


1、抛出受检异常Exception无法回滚

默认情况下,只有非受检异常RuntimeException、Error发生时,事务才会回滚。受检异常Exception发生时不会回滚。

图片来源:https://javadevcentral.com/checked-and-unchecked-exception-in-java

事务回滚源码:

代码语言:javascript
复制
org.springframework.transaction.interceptor.TransactionAspectSupport#completeTransactionAfterThrowing

默认情况下,非受检异常会回滚

我们可以设置回滚Exception异常类型,来解决受检异常不回滚的问题:

代码语言:javascript
复制
    @Transactional(rollbackFor=Exception.class)

处理逻辑如下:

代码语言:javascript
复制
org.springframework.transaction.interceptor.RuleBasedTransactionAttribute#rollbackOn

2、子事务出异常回滚当前事务,导致父方法也无法提交事务

事务的默认传播行为为Propagation.REQUIRED,子事务可以设置Propagation.REQUIRES_NEW,在独立事务中执行

3、方法内try catch异常,不再抛给事务框架,不会回滚事务

自己吞掉了异常,Spring框架不会探测到异常

4、事务多个业务有异步执行,异常不抛出,事务不会回滚

事务的实现涉及到java的ThreadLocal特性,如果异步执行,事务信息丢失或异常丢失,导致事务执行或回滚。

来源:https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#tx-decl-explained

5、一个事务中多个业务有同步或异步执行,使用不同的数据源,事务不会生效

使用spring的本地事务,同一个事务内必须一个数据源,不能跨数据源,否则必须使用分布式事务。

来源:https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#transaction-local

6、事务所在的类不是spring容器管理的

7、未配置事务管理器

8、其他aop 顺序问题,并且吞并异常,事务失效

事务aop有自己默认的顺序:

代码语言:javascript
复制
org.springframework.transaction.annotation.EnableTransactionManagement#order

如果其他开发者或者框架引入的aop顺序和事务的顺序相同,由于Spring框架aop排序问题,很可能导致一些问题的发生。

事务的坑:数据库引起的


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

事务的坑:大事务引发问题


1、锁定数据太多,容易造成大量阻塞或死锁问题和锁等待时间长而引发的锁超时问题;

2、回滚记录占用大量存储空间,事务回滚时间长;

3、并发情况下数据库连接处被占满;

4、事务执行时间长,事务结束后才写入binlog,容易造成数据库主从延迟

如何避免大事务:

1、不要一股脑的用@Transactional注解;

2、大事务拆分为独立的小事务;

3、事务避免PRC调用-分布式事务;

4、事务中避免一次处理太多的数据;

5、能不用事务就不用;

小结



本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-08-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 认知科技技术团队 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
分布式事务 DTF
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档