「这是我参与 2022 首次更文挑战的第 4 天,活动详情查看:2022 首次更文挑战」
穷则变,变则通,通则久。
在日常的 java 项目开发过程中,会为了保证业务操作的完整性,会在业务操作的整个过程和某个过程中使用到事务,利用事务来保障数据的一致性和完整性,避免数据错乱的发生。这里就从实战的角度出发,以 springboot 搭建的 ssm 项目来分享一下事务操作的注意事项。
配置事务的注意事项
在 springboot 项目中,事务配置生效的关注点:
1 开启事务注解 @EnableTransactionManagement
2 在配置文件中配置事务管理器,PlatformTransactionManager
3 需要开启事务的方法上加上注解 @Transactional
有以上的三点才能保障事务在项目中能够生效。
事务失效的场景
-
1 查看数据库中使用的表是否都是
InnoDB的引擎,有些表为了追求写入的性能,比如记录日志的表,会将引擎改为MyiSAM,如果数据库引擎不支持,那么添加的事务也就不会生效。 -
2 事务要加在
public方法上,否则事务将不会起作用,如果要用在非public方法上,事务不会生效。如果方法被final修饰,spring事务底层使用了aop, 也就是通过jdk动态代理或者cglib,生成了代理类,而被final或者staitc的方法,是不能重写或者代理,因此事务就不会生效。 -
3 在事务内部调用本类的另一个事务方法,那么被调用的一方事务不会生效。因为
spring的事务是使用动态代理生效的,本类内部的调用相当于是this.method的调用,没有经过spring代理所以事务不会生效。如果非要在类内部进行调用,需要按照如下图操作,updateUserInfo调用方法modifyUserInfo,需要使用AopContext获取当前对象进行调用执行。同时还要设置proxyTargetClass= true,改值默认为false。
- 4 注意事务设置的隔离级别,如果项目中配置了多个数据源,就会有多个事务管理器,在执行事务的时候需要指定其事务管理器。事务的传播属性和隔离级别是默认的,超时时间默认是
-1,不设置超时时间。异常回滚和异常不回滚需要根据业务的情况进行设置。
-
5 方法内部不能将异常
try-catch,如果方法内部都把异常给处理了,那么事务捕捉不到异常信息,事务自然不会回滚,也就不会生效。方法内部把异常信息给处理了,就不能被事务Aop拦截进行处理,自然就会进行回滚操作。 -
6 建议事务
@Transactional注解需要在具体的实现类上进行标注,而不是在接口层标注。注解是不能继承的,所以只有在基于接口的代理(PROXY)时事务才生效。如果正在使用基于类(AspectJ)代理时,那么注解不会被基于类的代理识别,对象也不会被事务代理所包装,因此事务是不能生效的。 -
7 多线程调用,在项目开发过程中多线程的应用场景是很多的,在多线程的场景下,主线程所在的
Context和多线程执行下的方法不在同一个上下文,我们知道spring的事务是通过数据库连接来实现的,数据库连接是存放在一个ThreadLocal中的,只有在同一个线程上下文下,事务的操作才能生效。
其它
在事务方法中,需要保证操作方法的内部只有 关于数据库的操作,诸如耗时的 IO 操作或者其它与业务无关的事情可以放在外部进行处理或者准备,这样能够降低单个事务的操作时间,提高系统的响应率和吞吐。