日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2024/4/17 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Transaction rolled back because it has been marked as rollback-only 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?http://hsyd.iteye.com/blog/586772

錯誤信息: Transaction rolled back because it has been marked as rollback-only? 原因:事務提交多次 檢查代碼 例:service嵌套service

=============================================================================

http://blog.csdn.net/fzfeng/article/details/5355257

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);
??? }

?

====================

http://my.oschina.net/jing31/blog/10414

原來是這樣設置的:

?? ? ? ?<tx:attributes>

?? ? ? ? ? ?<tx:method name="*" read-only="true"/>

?? ? ? ?</tx:attributes>

發現selectA調用selectB,如果selectB拋出Exception,selectA中捕獲Exception但是并不繼續向外拋出,最后會出現錯誤。

?

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

糾其原理其實很簡單,在selectB返回的時候,transaction被設置為rollback-only了,但是selectA正常消化掉,沒有繼續向外拋。

那么selectA結束的時候,transaction會執commit操作,但是transaction已經被設置為rollback-only了。

所以會出現這個錯誤。

有的同學說了,那不是沒得搞了,service不能拋出異常,或者不能攔截異常了?

其實不然,其實錯誤不在這里,而是select這種操作為什么要啟動事務呢?

調整好問題,找解決方案,問題就出現在propagation="REQUIRED"這個屬性上。

標準文檔上這樣寫:

MANDATORY?
??????????Support a current transaction, throw an exception if none exists.
NESTED?
??????????Execute within a nested transaction if a current transaction exists, behave like PROPAGATION_REQUIRED else.
NEVER?
??????????Execute non-transactionally, throw an exception if a transaction exists.
NOT_SUPPORTED?
??????????Execute non-transactionally, suspend the current transaction if one exists.
REQUIRED?
??????????Support a current transaction, create a new one if none exists.
REQUIRES_NEW?
??????????Create a new transaction, suspend the current transaction if one exists.
SUPPORTS?
??????????Support a current transaction, execute non-transactionally if none exists.

?

看來我們需要如下修改:

?? ? ? ?<tx:attributes>

?? ? ? ? ? ?<tx:method name="*" read-only="true" propagation="NOT_SUPPORTED"/>

?? ? ? ?</tx:attributes>

這樣select這樣的檢索操作根本就不啟動事務了,而且在有事務的方法中也是可以正常調用select方法的。

現在就沒問題了。

但是現在出現了另外一個問題,就是,如果在一個事物內對db進行操作,然后在出事物之前對剛才db操作的數據進行select是獲取不到修改結果的,為什么呢?因為not——supported是會在執行select之前掛起原有事物,不在原有事物內,當然無法獲得修改后的數據。

怎么辦?改成supports:

?? ? ? ?<tx:attributes>

?? ? ? ? ? ?<tx:method name="*" read-only="true" propagation="SUPPORTS"/>

?? ? ? ?</tx:attributes>

這個狀態用一句話概括就是“有則加入事物,無也不創建事物”。

?

總結

以上是生活随笔為你收集整理的Transaction rolled back because it has been marked as rollback-only的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。