Transaction is marked for rollback only or has timed out
程序员文章站
2022-05-23 11:28:52
...
Springboot,Activiti,Atomikos:
com.atomikos.datasource.xa.session.InvalidSessionHandleStateException: Transaction is marked for rollback only or has timed out
at com.atomikos.datasource.xa.session.NotInBranchStateHandler.checkEnlistBeforeUse(NotInBranchStateHandler.java:39)
at com.atomikos.datasource.xa.session.TransactionContext.checkEnlistBeforeUse(TransactionContext.java:70)
at com.atomikos.datasource.xa.session.SessionHandleState.notifyBeforeUse(SessionHandleState.java:160)
at com.atomikos.jdbc.AtomikosConnectionProxy.enlist(AtomikosConnectionProxy.java:207)
at com.atomikos.jdbc.AtomikosConnectionProxy.invoke(AtomikosConnectionProxy.java:122)
确认了bug原因:一开始由于并发导致了事务回滚,然后事务状态被标记为rollback,JTA中线程和事务状态是绑定关系,在线程被回收之前,这个线程所有调用oracle连接的sql,都会报rollback异常,直到线程被销毁。
看了下setRollbackOnly ()方法,发现最后是会把状态改为Active的:
RecoveryCoordinator addParticipant (
Participant participant ) throws SysException,
java.lang.IllegalStateException, RollbackException
{
synchronized ( fsm_ ) {
if ( !getState ().equals ( TxState.ACTIVE ) )
throw new IllegalStateException (
getCoordinatorId() +
" is no longer active but in state " +
getState ().toString () );
//FIRST add participant, THEN set state to support active recovery
if ( !participants_.contains ( participant ) ) {
participants_.add ( participant );
}
//make sure that aftercompletion notification is done.
setState ( TxState.ACTIVE );
}
return this;
}
如果这个方法抛出了异常:
void setRollbackOnly() {
RollbackOnlyParticipant p = new RollbackOnlyParticipant ( );
try {
addParticipant ( p );
} catch ( IllegalStateException alreadyTerminated ) {
//happens in rollback after timeout - see case 27857; ignore but log
if ( LOGGER.isTraceEnabled() ) LOGGER.logTrace ( "Error during setRollbackOnly" , alreadyTerminated );
} catch ( RollbackException e ) {
//ignore: corresponds to desired outcome
if ( LOGGER.isTraceEnabled() ) LOGGER.logTrace ( "Error during setRollbackOnly" , e );
}
}
可见Atomikos只是打印了一下异常信息(如果日志级别不是Trace就连日志都看不到),没做任何事。这就导致这个线程关联的事务永远处于异常状态,只要一有查询用到这个事务,就会在例行检查中报错:
TransactionContextStateHandler checkEnlistBeforeUse ( CompositeTransaction ct ) throws InvalidSessionHandleStateException
{
TransactionContextStateHandler ret = null;
if ( ct != null && ct.getProperty ( TransactionManagerImp.JTA_PROPERTY_NAME ) != null ) {
if ( TxState.MARKED_ABORT.equals ( ct.getState() ) ) {
//see case 27857
throw new InvalidSessionHandleStateException (
"Transaction is marked for rollback only or has timed out"
);
}
//JTA transaction found for calling thread -> enlist
//also see the state diagram documentation
ret = new BranchEnlistedStateHandler ( getXATransactionalResource() , ct , getXAResource() );
}
return ret;
}
出错了之后所有的后续处理都没能再更改事务的状态
if (ENLISTMENT_METHODS.contains(methodName)) {
try {
enlist();
} catch ( Exception e ) {
//fix for bug 25678
sessionHandleState.notifySessionErrorOccurred();
JdbcConnectionProxyHelper.convertProxyError ( e , "Error enlisting in transaction - connection might be broken? Please check the logs for more information..." );
}
}
上一篇: JAVA事务
下一篇: oj-广度优先遍历图-java
推荐阅读
-
Transaction has been rolled back because it has been marked as rollback
-
Transaction is marked for rollback only or has timed out
-
spring事务的[Transaction rolled back because it has been marked as rollback-only]浅析
-
用spring目标对象处理Transaction rolled back because it has been marked as rollback-only
-
用spring目标对象处理Transaction rolled back because it has been marked as rollback-only