Spring事务传播机制 港控/mmm° 2021-11-10 08:18 348阅读 0赞 **目录** 零、Spring事务大致流程。 一、代码层面。 二、详细拆分 。 三、举例精讲。 -------------------- ### 零、Spring事务大致流程。 ### 一般我们使用注解方式@Transitional,那么Spring容器首先会提取事务标签: 1、查看方法中是否存在事务声明;有则返回 2、否则,查看方法所在类中是否存在事务声明;有则返回 3、否则,如果存在接口,则到接口中去寻找;有则返回 拿到注解信息后就会解析详细的属性信息。 声明式事务处理主要步骤: a、获取事务属性;只有存在事务属性一切才可谈,否则其他功能无从谈起。 b、加载配置中配置的TransactionManager 。 c、不同事务处理方式使用不同的逻辑。 d、在目标方法执行前获取事务并收集事务信息。 事务信息和事务属性-也就是TransitionInfo和TransitionAttribute并不相同,TransitionInfo包含TransitionAttribute信息,但是除了TransitionAttribute外还有其他事务信息,如:PlatformTransactionManager以及TransitionStatus相关信息。 e、执行目标方法。 f、一旦出现异常,尝试异常处理。默认回滚运行时异常。 g、提交事务前的事务信息清楚。 h、提交事务。 ### 一、代码层面。 ### Spring中定义了其中事务传播行为: TransactionDefinition中定义如下 //传播机制 必须在一个事务内运行有则加入当前事务执行,否则创建新的事务执行 int PROPAGATION_REQUIRED = 0; //传播机制 支持事务:有则加入当前事务,没有则以非事务运行 int PROPAGATION_SUPPORTS = 1; //传播机制 强制:有则加入当前事务,没有则抛出异常 int PROPAGATION_MANDATORY = 2; //传播机制 创建一个新事务,如果当前存在事务,则将当前事务挂起 int PROPAGATION_REQUIRES_NEW = 3; //传播机制 以非事务方式运行,如果存在则挂起当前事务 int PROPAGATION_NOT_SUPPORTED = 4; //传播机制 以非事务方式运行,如果存在则抛出异常 int PROPAGATION_NEVER = 5; //传播机制 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行; //如果当前没有事务,则该取值等价于 PROPAGATION_REQUIRED int PROPAGATION_NESTED = 6; ### 二、详细拆分 。 ### <table> <thead> <tr> <th colspan="4" style="text-align:center;">支持事务</th> </tr> </thead> <tbody> <tr> <td colspan="2" style="width:245px;"><strong>PROPAGATION_REQUIRED</strong></td> <td colspan="2" style="width:568px;">当前存在事务,则加入;没有则新建事务</td> </tr> <tr> <td colspan="2" style="width:245px;"><strong>PROPAGATION_SUPPORTS</strong></td> <td colspan="2" style="width:568px;">当前存在事务,则加入;没有则以非事务运行</td> </tr> <tr> <td colspan="2" style="width:245px;"><strong>PROPAGATION_MANDATORY</strong></td> <td colspan="2" style="width:568px;">当前存在事务,则加入;没有则抛出异常</td> </tr> <tr> <td colspan="4" style="text-align:center;"><strong>不支持事务</strong></td> </tr> <tr> <td colspan="2" style="width:245px;"><strong>PROPAGATION_REQUIRES_NEW</strong></td> <td colspan="2" style="width:568px;">当前存在事务,则挂起;否则新建事务运行</td> </tr> <tr> <td colspan="2" style="width:245px;"><strong>PROPAGATION_NOT_SUPPORTE</strong></td> <td colspan="2" style="width:568px;">当前存在事务,则挂起;否则以非事务运行</td> </tr> <tr> <td colspan="2" style="width:245px;"><strong>PROPAGATION_NEVER</strong></td> <td colspan="2" style="width:568px;">当前存在事务,则抛出异常;否则以非事务运行</td> </tr> <tr> <td colspan="4" style="text-align:center;"><span style="color:#7c79e5;"><strong>特殊</strong></span></td> </tr> <tr> <td colspan="2" style="width:245px;"><strong>PROPAGATION_NESTED</strong></td> <td colspan="2" style="width:568px;">当前存在事务,则创建当前事务的嵌套事务运行,否则等同<strong>PROPAGATION_REQUIRED_NEW</strong></td> </tr> </tbody> </table> ### 三、举例精讲。 ### Spring采用声明式事务时,通过AOP来只是该声明式事务,会根据事务属性,自动在方法调用之前决定是否开启一个事务,并在方法执行之后决定事务提交或回滚事务。 **Propagation.REQUIRED Demo** @Transactional(propagation = Propagation.REQUIRED) methodA{ //调用methodB methodB(); } @Transactional(propagation = Propagation.REQUIRED) methodB(){ } 如果单独调用methodB: 因为此时不存在事务,根据事务传播机制的属性会新建一个事务,让methodB运行在这个事务当中。 如果单独调用methodA: 同理也会新建一个事务给methodA来运行,但是我们注意到methodB被methodA调用根据事务属性,此时存在一个事务,那么将methodB加入到methodA所在的事务中。 **PROPAGATION\_SUPPORTS Demo** @Transactional(propagation = Propagation.REQUIRED) methodA{ //调用methodB methodB(); } @Transactional(propagation = Propagation.SUPPORTS) methodB(){ } 如果单独调用methodB: 因为此时不存在事务,根据事务传播机制的属性,让methodB直接以非事务方式运行。 如果单独调用methodA: 同理也会新建一个事务给methodA来运行,但是我们注意到methodB被methodA调用根据事务属性,此时存在一个事务,那么将methodB加入到methodA所在的事务中。 **PROPAGATION\_MANDATORY Demo** @Transactional(propagation = Propagation.REQUIRED) methodA{ //调用methodB methodB(); } @Transactional(propagation = Propagation.MANDATORY) methodB(){ } 如果单独调用methodB: 因为此时不存在事务,根据事务传播机制的属性,运行methodB会直接抛出异常。 如果单独调用methodA: 同理也会新建一个事务给methodA来运行,但是我们注意到methodB被methodA调用根据事务属性,此时存在一个事务,那么methodB则加入到methodA所在的事务。 **PROPAGATION\_REQUIRES\_NEW Demo** @Transactional(propagation = Propagation.REQUIRED) methodA{ //调用methodB methodB(); } @Transactional(propagation = Propagation.REQUIRES_NEW) methodB(){ } 如果单独调用methodB: 因为此时不存在事务,根据事务传播机制的属性,运行methodB需要新建一个事务。 如果单独调用methodA: 同理也会新建一个事务给methodA来运行,但是我们注意到methodB被methodA调用根据事务属性,此时存在一个事务,那么此时需要将methodA所在的事务挂起,然后为methodB开启一个事务等待methodB执行完毕,然后恢复methodA被挂起的事务继续执行methodA事务。 methodA与methodB所对应的事务是两个独立的存在,彼此运行或者失败不影响对方,使用PROPAGATION\_REQUIRES\_NEW 需要使用 JtaTransactionManager事务管理器。 **PROPAGATION\_NOT\_SUPPORTE Demo** @Transactional(propagation = Propagation.REQUIRED) methodA{ //调用methodB methodB(); } @Transactional(propagation = Propagation.NOT_SUPPORTED) methodB(){ } 如果单独调用methodB: 因为此时不存在事务,根据事务传播机制的属性,运行methodB直接以非事务方式运行。 如果单独调用methodA: 同理也会新建一个事务给methodA来运行,但是我们注意到methodB被methodA调用根据事务属性,此时存在一个事务,那么此时需要将methodA所在的事务挂起,然后以非事务方式运行methodB。【需要使用JtaTransactionManager管理器】。 **PROPAGATION\_NEVER Demo** @Transactional(propagation = Propagation.REQUIRED) methodA{ //调用methodB methodB(); } @Transactional(propagation = Propagation.NEVER) methodB(){ } 如果单独调用methodB: 因为此时不存在事务,根据事务传播机制的属性,运行methodB直接以非事务方式运行。 如果单独调用methodA: 同理也会新建一个事务给methodA来运行,但是我们注意到methodB被methodA调用根据事务属性,此时存在一个事务,那么运行methodB则直接会抛出异常。 **PROPAGATION\_NESTED Demo** @Transactional(propagation = Propagation.REQUIRED) methodA{ //调用methodB methodB(); } @Transactional(propagation = Propagation.NESTED) methodB(){ } 如果单独调用methodB: 因为此时不存在事务,根据事务传播机制的属性,运行methodB需要新建一个事务。 如果单独调用methodA: 同理也会新建一个事务给methodA来运行,但是我们注意到methodB被methodA调用根据事务属性,此时存在一个事务,那么会将methodA的运行状态暂存一下,然后开启一个事务运行methodB,如果运行methodB失败则恢复到保存时的状态,如果运行methodB没有问题,代码继续执行,后续操作出错会回滚methodB所进行的操作。 嵌套事务:内层事务依赖于外层事务,外层事务失败的时候会回滚内层事务的所有操作,反之则不会。只有外部事务执行结束进行提交的时候才会将内层事务提交。内层事务是外层事务的子事务。
还没有评论,来说两句吧...