2014-10-08号早上06:50之后,系统一直在报UnexpectedRollbackException异常。
stackTrace:
org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:718) at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:475) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:270) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:91) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204) at com.sun.proxy.$Proxy76.executeStatisticUserHandleRank(Unknown Source)
碰到的问题大概可以简化成下面这样,伪代码大致如下:
ClassA.method(){
begin transaction;
beforeDone();
try
{
classB.doSomething(); //这里面有非受检异常抛出,所以标记为回滚, doSetRollbackOnly(status);
}catch(RuntimeException e)
{
}
afterDone();
commit;
end;
}
ClassB.doSomething()伪代码:
ClassB.doSomething(){
begin transaction;
/** do anything */ //这里会抛出一个runtime 的非受检异常
commit;
end;
}
这个是一个事务嵌套事务的例子,在spring里面我们配置了事务的传播机制是REQUIRED,所以这两个事务最终会合并成一个事务。程序中doSomething()中由于某某原因导致抛出异常(或者明确将该事务设置为了RollbackOnly),因为事务嵌套,ClassA.method()中有非受检异常抛出,标记并直接回滚,ClassB.doSomething()中有受检异常抛出,只是标记回滚状态,在调用回ClassA.method()中回滚,这个方法中ClassB.doSomething()有受检异常抛出,事务被标记为回滚,继续执行到ClassA.method(), 可是被捕获了,也就不回滚了,一直执行到最后commit。在commit时spring会判断回滚标志,若有回滚标记,回滚并抛出UnexpectedRollbackException异常,ransaction rolled back because it has been marked as rollback-only。