Spring嵌套事务问题

computerlibin 2018-02-24 05:20:59
问题现象比较奇怪,具体描述如下

假如有三个业务接口 ServiceA 、ServiceB和ServiceC, 其中 ServiceA 中有一个方法实现如下

/**
* 事务属性配置为 PROPAGATION_REQUIRED
*/
void methodA() {
//其他业务操作

// 调用 ServiceB 的方法
try{
ServiceB.methodB();
}catch(Exception e){
}

//其他业务操作
}


ServiceB的methodB方法实现如下:

/**
* 事务属性配置为 PROPAGATION_NESTED
*/
void methodB(){
ServiceC.methodC();
}

ServiceC的methodC方法实现如下:

/**
* 事务属性配置为 PROPAGATION_REQUIRED
*/
void methodC(){
//直接抛出异常
throw new RuntimeException();
}


此时调用methodA,则methodA执行结束spring框架代码提交事务时报如下异常:
[2018-02-24 17:02:29,444] (GlobalExceptionHandler.java:handle:35) [ERROR]: 运行时异常:
org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:720)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:521)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:291)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)

但我觉得外部事务应当可以成功提交,不应当抛出异常(内部事务methodB出异常后不应当影响外部事务methodA的提交,因为methodB是嵌套事务,并且在methodA中进行了try/catch)


奇怪的是如果将methodB的实现改为:

/**
* 事务属性配置为 PROPAGATION_NESTED
*/
void methodB(){
//ServiceC.methodC();
//不再调用methodC,直接抛异常
throw new RuntimeException();
}

则最外层事务methodA可以成功提交,不知道为什么多了一层methodC调用就会抛出异常。
静等大神提示~
...全文
1071 16 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
ouyangxiaokang6 2019-08-08
  • 打赏
  • 举报
回复
引用 6 楼 computerlibin 的回复:
引用 4 楼 whxjason 的回复:
在B中捕获一下serviceC.methodC试试
不能在B中捕获serviceC.methodC,因为methodB出异常后我希望能够回滚,捕获后就不能回滚了
你可以捕获异常后手动回滚B中的事物。B用独立的transaction,手动控制。
无休居士 2019-08-07
  • 打赏
  • 举报
回复
错了 捕捉了事务就会成功提交
无休居士 2019-08-07
  • 打赏
  • 举报
回复
你把方法后上都加上throws Exception,这样你说的第二种情况应该不会提交成功
computerlibin 2019-08-07
  • 打赏
  • 举报
回复
引用 12 楼 weixin_39460819 的回复:
因为a b c三个方法用的都是同一个连接,c异常的时候事务状态的rollback-only就被标注为true了
是这样的,跟到源码debug了下是这个原因
少伟_liu 2019-06-23
  • 打赏
  • 举报
回复
因为a b c三个方法用的都是同一个连接,c异常的时候事务状态的rollback-only就被标注为true了
computerlibin 2018-02-28
  • 打赏
  • 举报
回复
引用 10 楼 maradona1984 的回复:
[quote=引用 9 楼 computerlibin 的回复:] [quote=引用 8 楼 maradona1984 的回复:] spring的事务管理最好不要try catch,如果try catch也得抛出异常 你这个异常大概原因是,C抛出异常,AOP已经标记事务要回滚,但异常到A却被捕获,代码继续执行,然后提交事务,就会抛出该异常
对,从异常信息看原因是这样的,但是aop标记要回滚的事务是methodB这个内层的嵌套事务,methodA捕获了异常,methodA去提交事务时不应当影响methodB事务的回滚才对。 像在题目中描述的那样,如果在methodB中直接抛出异常而不调用methodC,则methodA可以提交成功,想不通为什么[/quote] 那得看看那spring事务传播机制配的什么了[/quote]methodA配置的REQUIRED,methodB配置的NESTED,methodC配置的REQUIRED,大神请进一步指导
maradona1984 2018-02-27
  • 打赏
  • 举报
回复
引用 9 楼 computerlibin 的回复:
[quote=引用 8 楼 maradona1984 的回复:] spring的事务管理最好不要try catch,如果try catch也得抛出异常 你这个异常大概原因是,C抛出异常,AOP已经标记事务要回滚,但异常到A却被捕获,代码继续执行,然后提交事务,就会抛出该异常
对,从异常信息看原因是这样的,但是aop标记要回滚的事务是methodB这个内层的嵌套事务,methodA捕获了异常,methodA去提交事务时不应当影响methodB事务的回滚才对。 像在题目中描述的那样,如果在methodB中直接抛出异常而不调用methodC,则methodA可以提交成功,想不通为什么[/quote] 那得看看那spring事务传播机制配的什么了
J-Exception 2018-02-26
  • 打赏
  • 举报
回复
引用 2 楼 computerlibin 的回复:
引用 1 楼 cm_1234 的回复:
你可以捕获一下异常试试,看是否是没有捕获异常导致的
在哪个进行catch?我在methodA中已经进行try/catch了
就像这样: /** * 事务属性配置为 PROPAGATION_REQUIRED */ void methodC(){ try { //直接抛出异常 throw new RuntimeException(); } catch (Exception e) { System.out.println("C抛出了异常"); } }
九零大叔芭蕉 2018-02-26
  • 打赏
  • 举报
回复
在B中捕获一下serviceC.methodC试试
computerlibin 2018-02-26
  • 打赏
  • 举报
回复
千万别沉帖啊,顶顶顶~
computerlibin 2018-02-26
  • 打赏
  • 举报
回复
引用 1 楼 cm_1234 的回复:
你可以捕获一下异常试试,看是否是没有捕获异常导致的
在哪个进行catch?我在methodA中已经进行try/catch了
computerlibin 2018-02-26
  • 打赏
  • 举报
回复
引用 8 楼 maradona1984 的回复:
spring的事务管理最好不要try catch,如果try catch也得抛出异常 你这个异常大概原因是,C抛出异常,AOP已经标记事务要回滚,但异常到A却被捕获,代码继续执行,然后提交事务,就会抛出该异常
对,从异常信息看原因是这样的,但是aop标记要回滚的事务是methodB这个内层的嵌套事务,methodA捕获了异常,methodA去提交事务时不应当影响methodB事务的回滚才对。 像在题目中描述的那样,如果在methodB中直接抛出异常而不调用methodC,则methodA可以提交成功,想不通为什么
maradona1984 2018-02-26
  • 打赏
  • 举报
回复
spring的事务管理最好不要try catch,如果try catch也得抛出异常 你这个异常大概原因是,C抛出异常,AOP已经标记事务要回滚,但异常到A却被捕获,代码继续执行,然后提交事务,就会抛出该异常
computerlibin 2018-02-26
  • 打赏
  • 举报
回复
引用 5 楼 cm_1234 的回复:
引用 2 楼 computerlibin 的回复:
[quote=引用 1 楼 cm_1234 的回复:] 你可以捕获一下异常试试,看是否是没有捕获异常导致的
在哪个进行catch?我在methodA中已经进行try/catch了
就像这样: /** * 事务属性配置为 PROPAGATION_REQUIRED */ void methodC(){ try { //直接抛出异常 throw new RuntimeException(); } catch (Exception e) { System.out.println("C抛出了异常"); } }[/quote]这个方法的异常我需要throw出去,不能这样catch住
computerlibin 2018-02-26
  • 打赏
  • 举报
回复
引用 4 楼 whxjason 的回复:
在B中捕获一下serviceC.methodC试试
不能在B中捕获serviceC.methodC,因为methodB出异常后我希望能够回滚,捕获后就不能回滚了
J-Exception 2018-02-25
  • 打赏
  • 举报
回复
你可以捕获一下异常试试,看是否是没有捕获异常导致的

67,549

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧