您的位置:首页 > 其它

Transaction rolled back because it has been marked as rollback-only

2010-03-08 09:46 627 查看
org.springframework.transaction.UnexpectedRollbackException:
Transaction rolled back because it has been marked as rollback-only

我遇到这个异常出现的情况是这样的: 配置事务拦截处理如下

<bean id="txProxy" abstract="true"

class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">

<property name="transactionManager" ref="transactionManager"/>

<property name="transactionAttributes">

<props>

<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>

<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>

<prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>

<prop key="query*">PROPAGATION_REQUIRED,readOnly</prop>

<prop key="is*">PROPAGATION_REQUIRED,readOnly</prop>

<prop key="*">PROPAGATION_REQUIRED,-java.lang.Exception</prop>

</props>

</property>

</bean>

如在一个save方法中去调一个load方法,因为事务属性配置都为PROPAGATION_REQUIRED,

所以两方法使用的是同一事务,而load方法不执行提交,(关于Spring声明式事务管理源码解读之事务提交,可见
http://ahuaxuan.javaeye.com/blog/89072)如果load方法出现异常,则org.springframework.transaction.interceptor.
TransactionInterceptor的invoke处理后则会抛出异常.执行completeTransactionAfterThrowing(txInfo, ex);

public Object invoke(final MethodInvocation invocation) throws Throwable {

// Work out the target class: may be <code>null</code>.

// The TransactionAttributeSource should be passed the target class

// as well as the method, which may be from an interface.

Class targetClass = (invocation.getThis() != null ? invocation.getThis().getClass() : null);

// If the transaction attribute is null, the method is non-transactional.

final TransactionAttribute txAttr =

getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass);

final String joinpointIdentification = methodIdentification(invocation.getMethod());

if (txAttr == null || !(getTransactionManager() instanceof CallbackPreferringPlatformTransactionManager)) {

// Standard transaction demarcation with getTransaction and commit/rollback calls.

TransactionInfo txInfo = createTransactionIfNecessary(txAttr, joinpointIdentification);

Object retVal = null;

try {

// This is an around advice: Invoke the next interceptor in the chain.

// This will normally result in a target object being invoked.

retVal = invocation.proceed();

}

catch (Throwable ex) {

// target invocation exception

completeTransactionAfterThrowing(txInfo, ex);

throw ex;

}

finally {

cleanupTransactionInfo(txInfo);

}

commitTransactionAfterReturning(txInfo);

return retVal;

}

else {

// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.

try {

Object result = ((CallbackPreferringPlatformTransactionManager) getTransactionManager()).execute(txAttr,

new TransactionCallback() {

public Object doInTransaction(TransactionStatus status) {

TransactionInfo txInfo = prepareTransactionInfo(txAttr, joinpointIdentification, status);

try {

return invocation.proceed();

}

catch (Throwable ex) {

if (txAttr.rollbackOn(ex)) {

// A RuntimeException: will lead to a rollback.

if (ex instanceof RuntimeException) {

throw (RuntimeException) ex;

}

else {

throw new ThrowableHolderException(ex);

}

}

else {

// A normal return value: will lead to a commit.

return new ThrowableHolder(ex);

}

}

finally {

cleanupTransactionInfo(txInfo);

}

}

});

// Check result: It might indicate a Throwable to rethrow.

if (result instanceof ThrowableHolder) {

throw ((ThrowableHolder) result).getThrowable();

}

else {

return result;

}

}

catch (ThrowableHolderException ex) {

throw ex.getCause();

}

}

}

completeTransactionAfterThrowing方法源码如下: 根据TransactionInfo的事务属性判断处理的异常是否需要做

rollback处理,从来根据事务状态来回滚事务.

protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) {

if (txInfo != null && txInfo.hasTransaction()) {

if (logger.isTraceEnabled()) {

logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +

"] after exception: " + ex);

}

if (txInfo.transactionAttribute.rollbackOn(ex)) {

try {

getTransactionManager().rollback(txInfo.getTransactionStatus());

}

catch (TransactionSystemException ex2) {

logger.error("Application exception overridden by rollback exception", ex);

ex2.initApplicationException(ex);

throw ex2;

}

catch (RuntimeException ex2) {

logger.error("Application exception overridden by rollback exception", ex);

throw ex2;

}

catch (Error err) {

logger.error("Application exception overridden by rollback error", ex);

throw err;

}

}

else {

// We don't roll back on this exception.

// Will still roll back if TransactionStatus.isRollbackOnly() is true.

try {

getTransactionManager().commit(txInfo.getTransactionStatus());

}

catch (TransactionSystemException ex2) {

logger.error("Application exception overridden by commit exception", ex);

ex2.initApplicationException(ex);

throw ex2;

}

catch (RuntimeException ex2) {

logger.error("Application exception overridden by commit exception", ex);

throw ex2;

}

catch (Error err) {

logger.error("Application exception overridden by commit error", ex);

throw err;

}

}

}

}

org.springframework.transaction.support.AbstractPlatformTransactionManager的rollback方法如下:

如果事务状态是未完成的则抛出IllegalTransactionStateException,否则则根据此事务状态处理事务回滚。

public final void rollback(TransactionStatus status) throws TransactionException {

if (status.isCompleted()) {

throw new IllegalTransactionStateException(

"Transaction is already completed - do not call commit or rollback more than once per transaction");

}

DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;

processRollback(defStatus);

}

执行processRollback方法,如果status有事务,事务是部分失败全局回滚。则执行实现类HibernateTransaction

Manager的doSetRollbackOnly()方法。

private void processRollback(DefaultTransactionStatus status) {

try {

try {

triggerBeforeCompletion(status);

if (status.hasSavepoint()) {

if (status.isDebug()) {

logger.debug("Rolling back transaction to savepoint");

}

status.rollbackToHeldSavepoint();

}

else if (status.isNewTransaction()) {

if (status.isDebug()) {

logger.debug("Initiating transaction rollback");

}

doRollback(status);

}

else if (status.hasTransaction()) {

if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {

if (status.isDebug()) {

logger.debug(

"Participating transaction failed - marking existing transaction as rollback-only");

}

doSetRollbackOnly(status);

}

else {

if (status.isDebug()) {

logger.debug(

"Participating transaction failed - letting transaction originator decide on rollback");

}

}

}

else {

logger.debug("Should roll back transaction but cannot - no transaction available");

}

}

catch (RuntimeException ex) {

triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);

throw ex;

}

catch (Error err) {

triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);

throw err;

}

triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);

}

finally {

cleanupAfterCompletion(status);

}

}

HibernateTransactionManager的doSetRollbackOnly()方法:将HibernateTransactionObject设置为rollbackonly.

protected void doSetRollbackOnly(DefaultTransactionStatus status) {

HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();

if (status.isDebug()) {

logger.debug("Setting Hibernate transaction on Session [" +

SessionFactoryUtils.toString(txObject.getSessionHolder().getSession()) + "] rollback-only");

}

txObject.setRollbackOnly();

}

public void setRollbackOnly() {

getSessionHolder().setRollbackOnly();

if (hasConnectionHolder()) {

getConnectionHolder().setRollbackOnly();

}

}

正如前面所说的, 两个方法:save,load同属于一个事务,而load事务产生异常,修改了sessionHolder和connection

Holder的rollbackonly属性为true.

而当save执行commit的时候,判断事务状态是否为全局回滚(就是判断HibernateTransactionObject的sessionHolder

和connectionHolder是否为rollbackonly),此时的rollbackonly属性则为true。处理完回滚后,继续判断事务状态是否为

新事务(因为save方法启用时是新建立的一个事务,而load方法则是使用同一事务),所以则抛出了UnexpectedRollbackException

public final void commit(TransactionStatus status) throws TransactionException {

if (status.isCompleted()) {

throw new IllegalTransactionStateException(

"Transaction is already completed - do not call commit or rollback more than once per transaction");

}

DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;

if (defStatus.isLocalRollbackOnly()) {

if (defStatus.isDebug()) {

logger.debug("Transactional code has requested rollback");

}

processRollback(defStatus);

return;

}

if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {

if (defStatus.isDebug()) {

logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");

}

processRollback(defStatus);

// Throw UnexpectedRollbackException only at outermost transaction boundary

// or if explicitly asked to.

if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {

throw new UnexpectedRollbackException(

"Transaction rolled back because it has been marked as rollback-only");

}

return;

}

processCommit(defStatus);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐