Spring事务:UnexpectedRollbackException:

UnexpectedRollbackException

org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

问题产生的原因: 类中的子事务抛出异常后,子事务已经回滚,spring就已经标记的回滚状态(rollback-only),主事务在被提交时就会报上述错误。

举例子说明(花了半天一点一点验证的,其中还了解了spring事务的几个级别)

 

A→B→C

举例说明 下面ABC代表三个类  A调用B,B调用C,其中C中操作数据库,B类做业务逻辑处理,要求在业务逻辑报错的情况下,不报错返回异常信息即可{return message};现在B业务已经抛出异常并且要返回message此时再返回数据,C也要回滚事务;

代码如下: A B  C调用关系的三个方法  测试使用

A.method(){

 

B.method();    

}

}

=======================================

B.method(){

try{

C.method();

}catch(Exception e){

}

return   message;

}

=====================================

C.method() {

try{

    add("数据");

 

}catch(Exception e){

}

//更好的区分 单独定义一个异常

try{

  

throw new BusinessException("报错")

}catch(Exception e){

throw new BusinessException("报错");//自定义异常

}

}

===========================================

报错:

 

###分析一

可以看到在C抛出异常后,B在拿到异常继续走完流程也要提交事务,此时就会产生上述报错信息;

问题分析:Spring源码中有 Geting  transaction for

Geting  transaction for(C).....动作完成,已经把事务标记rollback-only,

继续Geting  transaction for(B) 报错 Transaction has been rolled back because it has been marked as rollback错误

org.springframework.transaction.support.AbstractPlatformTransactionManager中

/**
 * Return whether to globally mark an existing transaction as rollback-only
 * after a participating transaction failed.
 */
public final boolean isGlobalRollbackOnParticipationFailure() {
   return this.globalRollbackOnParticipationFailure;
}

参数默认true

当这个参数为false时会让主事务决定回滚,这个可以有调用方决定。但是只适用数据访问失败且所有操作事务提交,显而易见这个要依据自己需求而定,可以解决刚刚问题;

###解决办法一:

添加<property name="globalRollbackOnParticipationFailure" value="false" />   控制台有返回,数据也写入了 没有回滚

<bean name="transactionManager"

class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="dataSource" ref="mips_dataSource"></property>

<property name="globalRollbackOnParticipationFailure" value="false" />

</bean>

 

 

结局办法:配置 A B类的事务,把事务给去除掉,这样即使A B出现异常也会继续执行,不会影响C的事务处理

<aop:pointcut id="interceptorPointCuts"

expression="execution(* com.th.supcom.mips.impl.service..*.*(..))

and !execution(* com.th.supcom.mips.impl.service.internal.core.AtmServiceImpl.*(..))

and !execution(* com.th.supcom.mips.impl.service.external.AtmOutpSettlementServiceImpl.*(..))/>

<aop:advisor advice-ref="txAdvice" pointcut-ref="interceptorPointCuts" />

</aop:config>

 

###分析二:

上述问题我们可以结合具体需求,比如问题,B有报错但是会继续返回异常信息,也就是要吃掉这个事务,信息正常放回;

断点提示中也有一个AopUtils,也说明产生了不同的事务,且违背了面向切面的原理;我们可以从配置切面参数来管理是否需要事务;

参数配置:

<aop:pointcut id="interceptorPointCuts"

expression="execution(* com.bai.du.www.impl.service..*.*(..))

and !execution(* om.bai.du.www.impl.service.B.*(..))                     ----------剔除B事务 也可以配置具体方法

and !execution(* om.bai.du.www.impl.service.A*(..))/>                   -----------剔除C事务

<aop:advisor advice-ref="txAdvice" pointcut-ref="interceptorPointCuts" />

</aop:config>

首先要清楚C处理数据事务肯定要回滚,所以需要事务(剔除C数据修改,报错后数据不会回滚),但是如果我们只配置B不要事务,可以试运行下

结果还是报错:  A也会提交,所以要把A B 都要配置进去;体现事务的原子性

这里的例子可以验证  事务必须服从ISO/IEC所制定的ACID原则。ACID是原子性(atomicity)、一致性(consistency)、隔离性(isolation)和持久性(durability)   {自己可以动手试试可以更好的理解}

 

所以为了不影响整体项目事务配置和回滚参数设置,推荐使用方法二处理该问题;

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值