springboot中使⽤@Transactional注解事物不⽣效的坑
⼀:在springboot中使⽤事物遇到的坑
1.我们知道spring中的事物分为两种:⼀种是编程式事物,⼀种是声明式事物。顾名思义,编程式事物是指通过代码去实现事物管理,这⾥不做过多说明。另⼀种是声明式事物,分为两种情况01:⼀种是通过传统xml⽅式配置,02:使⽤@Transaction注解⽅式配置,这是主要讲解的是通过注解⽅式配置。因为在springboot项⽬中,会⾃动配置DataSourceTransactionManager,我们只需要在对应的⽅法上或者类上加上@Transaction就会⾃动接⼊到spring的事物中,让spring管理。
2.继续踩坑
**01坑:**如下图所⽰,我这边本地调⽤接⼝修改数据库张三⼝袋⾥⾯的⾦额,并且启⽤了事物管理,抛出RuntimeExecption。这时我们调⽤接⼝,我们可以看到事物⽣效了,数据库⾥⾯值并没有发⽣改变。但是,当我们把抛出的异常改为
throw new SQLTimeoutException(); 调⽤接⼝的时候,发现数据库张三的⾦额被改变了,事物没起作⽤,明明开启了事物,但是没起作⽤,这是为什么呢?
02坑:在我们需要执⾏事物的⽅法,如果对异常进⾏抛出,并且我们⼿动捕获了这个异常的话,这时候事物也不会起作⽤的。如下图所⽰:
03坑:@Transaction注解只对⽅法名为pubic的才⽣效,其他事物不会⽣效。
04坑:默认情况下,只有来⾃外部的⽅法调⽤才会被AOP代理捕获,也就是,类内部⽅法调⽤本类内部的其他⽅法并不会引起事务⾏为,即使被调⽤⽅法使⽤@Transactional注解进⾏修饰。
3.解决⽅案
01:Spring的事务管理默认是针对Error异常和RuntimeException异常以及其⼦类进⾏事务回滚。对runtimeException并不需要抛出,error需要抛出异常,并进⾏捕获。所以我们上⾯⽤到的SQLTimeoutException()并不属于这两者之间,我们需要⼿动回滚异常,在@Transaction注解⾥⾯指
定回滚异常类型即可,我这⾥举⼀个例⼦@Transactional(rollbackFor = Exception.class) 02:我们在需要执⾏的sercvice⾥⾯不应该主动捕获异常,这会导致我们事物不⽣效,应该继续往上抛,在controller层捕获即可,这样事物也⽣效了,异常也捕获了。
03:@Transaction注解只对⽅法名为pubic的才⽣效,其他事物不会⽣效。顾名思义,也就是说使⽤了@Transaction注解的,只能是public。因为只有@Transaction注解只有被其他⽅法调⽤才⽣效的,能被其他⽅法调⽤的⽅法,只能是public。
04:我们在使⽤事物注解的时候,尽量不要在类上⾯使⽤,这会使得类⾥⾯的所有⽅法都会有事物进⾏处理。⽐如说,我们⼀些⽅法只做查询操作,我们就没有必要再进⾏事物,我们应该在需要事物处理的⽅法上⾯加事物,并且指定回滚的异常类型。
⼆:既然说到spring的事物了,再说⼀下spring事物的隔离级别吧
public enum Isolation {
DEFAULT(-1),
READ_UNCOMMITTED(1),
READ_COMMITTED(2),
REPEATABLE_READ(4),
SERIALIZABLE(8);
}
springboot aopDEFAULT :这是默认值,表⽰使⽤底层数据库的默认隔离级别。对⼤部分数据库⽽⾔,通常这值就是: READ_COMMITTED 。
READ_UNCOMMITTED :该隔离级别表⽰⼀个事务可以读取另⼀个事务修改但还没有提交的数据。该级别不能防⽌脏读和不可重复读,因此很少使⽤该隔离级别。
READ_COMMITTED :该隔离级别表⽰⼀个事务只能读取另⼀个事务已经提交的数据。该级别可以防⽌脏读,这也是⼤多数情况下的推荐值。
REPEATABLE_READ :该隔离级别表⽰⼀个事务在整个过程中可以多次重复执⾏某个查询,并且每次返回的记录都相同。即使在多次查询之间有新增的数据满⾜该查询,这些新增的记录也会被忽略。该级别可以防⽌脏读和不可重复读。
SERIALIZABLE :所有的事务依次逐个执⾏,这样事务之间就完全不可能产⽣⼲扰,也就是说,该级
别可以防⽌脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会⽤到该级别。
指定⽅法:通过使⽤ isolation 属性设置,例如:@Transactional(isolation = Isolation.DEFAULT)
Propagation:传播⾏为
所谓事务的传播⾏为是指,如果在开始当前事务之前,⼀个事务上下⽂已经存在,此时有若⼲选项可以指定⼀个事务性⽅法的执⾏⾏为。
我们可以看 ansaction.annotation.Propagation 枚举类中定义了6个表⽰传播⾏为的枚举值:
public enum Propagation {
REQUIRED(0),
SUPPORTS(1),
MANDATORY(2),
REQUIRES_NEW(3),
NOT_SUPPORTED(4),
NEVER(5),
NESTED(6);
}
REQUIRED :如果当前存在事务,则加⼊该事务;如果当前没有事务,则创建⼀个新的事务。
SUPPORTS :如果当前存在事务,则加⼊该事务;如果当前没有事务,则以⾮事务的⽅式继续运⾏。
MANDATORY :如果当前存在事务,则加⼊该事务;如果当前没有事务,则抛出异常。
REQUIRES_NEW :创建⼀个新的事务,如果当前存在事务,则把当前事务挂起。
NOT_SUPPORTED :以⾮事务⽅式运⾏,如果当前存在事务,则把当前事务挂起。
NEVER :以⾮事务⽅式运⾏,如果当前存在事务,则抛出异常。
NESTED :如果当前存在事务,则创建⼀个事务作为当前事务的嵌套事务来运⾏;如果当前没有事务,则该取值等价于 REQUIRED 。
指定⽅法:通过使⽤ propagation 属性设置,例如:@Transactional(propagation = Propagation.REQUIRED)
到此这篇关于springboot中使⽤@Transactional注解事物不⽣效的原因的⽂章就介绍到这了,更多相关springboot @Transactional不⽣效内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。