事务什么时候生效,你真的了解吗?置信很多小伙伴在面试过程常常会被面试官问到[email protected]什么时候会生效?带着这个问题,我先从以下四个生效的例子,讲述生效的场景,先让咱们初步有个大略的理解,而后再通过源码的解读,剖析@Transactional生效的起因,从而防止当前在工作中踩坑。
@Transactional 生效场景
- 公有办法(拜访权限修饰符为private的办法)
- 异样类型不匹配
- 同类非事务办法调用事务办法
- 多线程
示例1:公有办法
应用private润饰@Transactional注解的办法,因为idea会查看实现类办法的拜访权限修饰符,所以此处不进行测试。
示例2:异样类型不匹配
这是因为咱们在写@Transactional后没有设置回滚类型导致,这个在idea中会有黄色正告线标识-办法【exceptionType】须要在Transactional注解指定rollbackFor或者在办法中显式的rollback。提醒咱们指定回滚异样类型,防止产生意料之外的后果。
@Override@Transactionalpublic void exceptionType(boolean isEnableRollbackException) throws IOException { userMapper.insert(User.builder().name("cpz").age(18).email("[email protected]").build()); if (isEnableRollbackException) { throw new RuntimeException("RUNTIME Exception"); } else { throw new IOException("IOE Exception"); }}
代码解析:本例通过向数据库新增一条用户数据,而后抛出不同类型的异样(通过布尔类型参数isEnableRollbackException
管制),最初察看该条数据是否在数据库里,即可实现类型异样的测试。
示例3:同类非事务办法调用事务办法
这是因为@Transactional是基于 aop 实现的,而 aop 应用动静代理实现,通过代理间接调用办法,会在办法前后加上事务相干逻辑。而当初间接通过类外部办法调用,则不会在办法前后生成事务相干逻辑,自然而然事务也会生效。
@Overridepublic void internalMethod() { this.insertUser(); throw new RuntimeException("Runtime Exception");}@Transactionalpublic void insertUser() { userMapper.insert(User.builder().name("cpz").age(18).email("[email protected]").build());}
代码解析:通过申明事务办法insertUser
,而后应用同类办法internalMethod
间接调用,从而绕过动静代理对象的加强-开启事务,提交事务等逻辑。最初察看该条数据是否在数据库里,即可实现同类非事务办法调用事务办法的测试。
示例4:多线程
因为父子线程是绝对独立的,因而它们的之间的事务不是同一个的,所以不论是父线程抛出异样还是在子线程中抛出异样,对于另外的线程是不受影响的。
@Overridepublic void multiThread(boolean isThrowFromParentThread) { if (isThrowFromParentThread) { new Thread(() -> { userMapper.insert(User.builder().name("cpz").age(18).email("[email protected]").build()); }).start(); throw new RuntimeException(); } else { new Thread(() -> { userMapper.insert(User.builder().name("cpz").age(18).email("[email protected]").build()); throw new RuntimeException(); }).start(); }}
代码解析:通过参数isThrowFromParentThread
管制是父子线程抛出异样。最初察看该条数据是否在数据库里,即可实现多线程办法的测试。
源码解读:
1、ReflectiveMethodInvocation#proceed()
首先会通过一个拦截器interceptorOrInterceptionAdvice(TransactionInterceptor)
,执行invoke(this)办法,this为ReflectiveMethodInvocation
对象实例,外面蕴含咱们测试的代理对象,办法、参数等属性。
TransactionInterceptor#invoke(invocation)
2、执行办法之后会进入事务办法invokeWithinTransaction
,此处是咱们事务的外围,蕴含:1、获取事务属性后开启事务、2、指标办法的调用、3、事务的回滚、4、事务的提交,对示例的事务生效问题会在这里解惑。
第一步获取事务属性会调用computeTransactionAttribute
办法实现属性的获取
外面会去判断是否为public润饰的办法,所以这也是示例1公有办法不行的起因
接下来看看第三步事务的回滚
回滚事务条件
而默认只有运行时异样(RuntimeException
)和谬误(ERROR
)会回滚
所以示例2不配置rollbackFor = Exception.class
会出现异常类型不匹配状况从而导致事务生效。
这里介绍下异样类的档次
「学习交换」
能够扫上面二维码,关注「我的极简博客」公众号。
始终在谋求思路的传递而非代码的COPY
本文由mdnice多平台公布