欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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 Atomikos