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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

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

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

spring的聲明事務提供了強大功能,讓我們把業務關注和非業務關注的東西又分離開了。好東西的使用,總是需要有代價的。使用聲明事務的時候,一 個不小心經常會碰到“Transaction rolled back because it has been marked as rollback-only”這個異常。有時候又常常會納悶,"我已經try-catch了,為什么還這樣呢?"

?

Xml代碼 ?
  • <!--?0?placeHolder?-->??
  • <bean??class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">??
  • ????<property?name="locations">??
  • ????????<list>??
  • ????????????<value>files/pro.properties</value>??
  • ????????</list>??
  • ????</property>??
  • </bean>??
  • ??
  • <!--?1?dataSource?-->??
  • <bean?id="dataSource"?class="org.springframework.jdbc.datasource.DriverManagerDataSource">??
  • ????<property?name="driverClassName"?value="com.mysql.jdbc.Driver"></property>??
  • ????<property?name="url"?value="${jdbc.mysql.url}"></property>??
  • ????<property?name="username"?value="${jdbc.username}"></property>??
  • ????<property?name="password"?value="${jdbc.userpassword}"></property>??
  • </bean>??
  • ??
  • <!--?2?jdbcTemplate?-->??
  • <bean?id="jdbcTemplate"?class="org.springframework.jdbc.core.JdbcTemplate">??
  • ????<property?name="dataSource"?ref="dataSource"></property>??
  • </bean>??
  • ??
  • <!--?3?BaseDao?-->??
  • <bean?id="baseDao"?class="transaction.dao.BaseDao"?abstract="true">??
  • ????<property?name="jdbcTemplate"?ref="jdbcTemplate"?/>??
  • </bean>??
  • ??
  • <bean?id="aDao"?class="transaction.dao.Adao"?parent="baseDao">??
  • </bean>??
  • ??
  • <bean?id="bDao"?class="transaction.dao.Bdao"?parent="baseDao">???
  • </bean>??
  • ??
  • <!--?4?service?-->??
  • <bean?id="aBo"?class="transaction.bo.AboImpl">??
  • ????<property?name="aDao"?ref="aDao"?/>??
  • ????<property?name="bBo"?ref="bBo"?/>??
  • </bean>??
  • ??
  • <bean?id="bBo"?class="transaction.bo.BboImpl">??
  • ????<property?name="bDao"?ref="bDao"?/>??
  • </bean>??
  • ??
  • <!--?5?transaction?-->??
  • <bean?id="transactionManager"?class="org.springframework.jdbc.datasource.DataSourceTransactionManager">??
  • ????<property?name="dataSource"?ref="dataSource"?/>??
  • </bean>??
  • ??
  • <bean?id="transactionInterceptor1"?class="org.springframework.transaction.interceptor.TransactionInterceptor"?>??
  • ????<property?name="transactionManager"?ref="transactionManager"></property>??
  • ????<property?name="transactionAttributes">??
  • ????????<props>??
  • ????????????<prop?key="*">PROPAGATION_REQUIRED</prop>??
  • ????????</props>????
  • ????</property>??
  • </bean>??
  • ??
  • <bean?id="autoProxy1"??class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">??
  • ????<property?name="beanNames">??
  • ????????<list>??
  • ????????????<value>*Bo</value>??
  • ????????</list>??
  • ????</property>??
  • ????<property?name="interceptorNames">??
  • ????????<list>??
  • ????????<!--???
  • ????????????<value>transactionInterceptor2</value>?
  • ????????????-->??
  • ????????????<value>transactionInterceptor1</value>????
  • ????????</list>??
  • ????</property>??
  • </bean>??
  • ?這里的聲明事務是作用于所有以Bo為后綴的bean的所有方法上,使用REQUIRED傳播方式。

    Java代碼 ?
  • public?int?insertA(A?a)???
  • {??
  • ????aDao.insertA(a);??
  • ??????
  • ????B?b?=?new?B();??
  • ????b.setName("bbb");??
  • ????try??
  • ????{??
  • ????????bBo.insertB(b);??
  • ????}??
  • ????catch(Exception?e)??
  • ????{??
  • ????????System.out.println("aaa");??
  • ????}??
  • ????return?0;??
  • }??
  • ?這里,insertA 開始一個事務,調用aDao.insertA(a)[一個簡單的數據庫操作],然后調用 bBo.insertB(b)[bo調dao,dao直接拋異常]。bBo的insertB方法,也要開始一個事務,但是這里的傳播機制是 REQUIRED。OK,和insertA 的事務合二為一吧。因為bBo.insertB(b)會拋異常出來,這里try-catch下,希望aDao.insertA(a)的操作能夠成功。

    但是現實總是殘酷的,這里會有一個大大的 “Transaction rolled back because it has been marked as rollback-only” ,結果你會發現aDao.insertA(a)的操作也沒有成功。

    ?

    try-catch不起作用的原因簡單的說就是,try-catch的不是地方,你認為你的try-catch是最接近異常拋出點了,是第一個處理 的handler了。實際上,spring在更早一步就try-catch 住了,同時還設置了一些標志位,再把catch住的異常往外拋。這個時候才是我們的try-catch。而"Transaction rolled back because it has been marked as rollback-only"就是因為事務在提交的時候,發現標志位已經被設置了,不應該去提交了,然后吭哧吭哧的回滾調,再提示你已經被設置成 rollback-only了。

    ?

    原因是既然如此,那么在不改變代碼的情況下,依靠配置能否解決這個問題呢?使用PROPAGATION_REQUIRES_NEW吧。對于 bBo.insertB(b)開個新的事務,如果失敗了就回滾調,不影響外面的insertA不就OK了。最簡單的情況就是在 transactionInterceptor1前面,再加個攔截器transactionInterceptor2,該攔截器只針對insertB的事 務屬性進行修改。

    Xml代碼 ?
  • <bean?id="autoProxy1"??class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">??
  • ????<property?name="beanNames">??
  • ????????<list>??
  • ????????????<value>*Bo</value>??
  • ????????</list>??
  • ????</property>??
  • ????<property?name="interceptorNames">??
  • ????????<list>??
  • ???????????
  • ????????????<value>transactionInterceptor2</value>??
  • ??????????????
  • ????????????<value>transactionInterceptor1</value>????
  • ????????</list>??
  • ????</property>??
  • </bean>??
  • ??
  • ??
  • <bean?id="transactionInterceptor2"?class="org.springframework.transaction.interceptor.TransactionInterceptor"?>??
  • ????<property?name="transactionManager"?ref="transactionManager"></property>??
  • ????<property?name="transactionAttributes">??
  • ????????<props>??
  • ????????????<prop?key="insertB">PROPAGATION_REQUIRES_NEW</prop>??
  • ????????</props>????
  • ????</property>??
  • </bean>??
  • 注意interceptorNames里面元素的位置。先要使用transactionInterceptor2,再使用 transactionInterceptor1.因為調用insertB的時候,transactionInterceptor2先開了一個新事務,而 后transactionInterceptor1融合進這個事務。如果這2個攔截器的順序顛倒的話,那么還是會出現“Transaction rolled back because it has been marked as rollback-only”。因為,transactionInterceptor2生成事務回滾以后,還是會把ex拋給 transactionInterceptor1。這個時候,transactionInterceptor1的事務和insertA的事務是同一個。 transactionInterceptor1,把標志設置好,等到insertA真的結束的時候,因為異常被我們的try-catch捕獲 了,spring就會發現需要提交的事務具有一個已經被標記號的rollback。所以就又拋出來了。

    ?

    但是如果系統有很多遺留的因素導致你不敢盲目的修改配置文件的話(比如事務的poincut),那么我們就再加一個事務proxy就OK了。

    Xml代碼 ?
  • <bean?id="autoProxy2"?class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">??
  • ????????<property?name="beanNames">??
  • ????????????<list>??
  • ????????????????<value>*Bo</value>??
  • ????????????</list>??
  • ????????</property>??
  • ????????<property?name="interceptorNames">??
  • ????????????<list>??
  • ????????????????<value>transactionInterceptor2</value>??
  • ????????????????<!--???
  • ????????????????<value>transactionInterceptor1</value>???
  • ????????????????-->??
  • ????????????</list>??
  • ????????</property>??
  • ????</bean>??
  • ??????
  • ????<bean?id="autoProxy1"??class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">??
  • ????????<property?name="beanNames">??
  • ????????????<list>??
  • ????????????????<value>*Bo</value>??
  • ????????????</list>??
  • ????????</property>??
  • ????????<property?name="interceptorNames">??
  • ????????????<list>??
  • ????????????<value>transactionInterceptor1</value>????
  • ????????????<!--???
  • ????????????<value>transactionInterceptor2</value>???????
  • ????????????-->????????
  • ????????????</list>??
  • ????????</property>??
  • ????</bean>??
  • 如上的配置還是會帶來悲劇的“Transaction rolled back because it has been marked as rollback-only”。

    ?

    但是如果我們把 autoProxy2 放到 autoProxy1 或者給自動代理加上順序的話。。。結果就是喜劇了。。

    Xml代碼 ?
  • <bean?id="autoProxy1"??class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">??
  • ????????<property?name="beanNames">??
  • ????????????<list>??
  • ????????????????<value>*Bo</value>??
  • ????????????</list>??
  • ????????</property>??
  • ????????<property?name="interceptorNames">??
  • ????????????<list>??
  • ????????????<value>transactionInterceptor1</value>????
  • ????????????<!--???
  • ????????????<value>transactionInterceptor2</value>???????
  • ????????????-->????????
  • ????????????</list>??
  • ????????</property>??
  • ????</bean>??
  • ??????
  • ??????
  • ????<bean?id="autoProxy2"?class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">??
  • ????????<property?name="beanNames">??
  • ????????????<list>??
  • ????????????????<value>*Bo</value>??
  • ????????????</list>??
  • ????????</property>??
  • ????????<property?name="interceptorNames">??
  • ????????????<list>??
  • ????????????????<value>transactionInterceptor2</value>??
  • ????????????????<!--???
  • ????????????????<value>transactionInterceptor1</value>???
  • ????????????????-->??
  • ????????????</list>??
  • ????????</property>??
  • ????</bean>??
  • ?

    ?

    造成這個原因是由使用了2個代理的順序導致的。

    在做自動代理的時候,spring會按照postBeanProcessor bean聲明的順序(如果沒有設置順序的話),來依次處理bean。如果autoProxy2 在 autoProxy1 之前,這樣transactionInterceptor2 就會更加貼近insertB的調用,其效果就像

    Xml代碼 ?
  • <bean?id="autoProxy1"??class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">??
  • ????????<property?name="beanNames">??
  • ????????????<list>??
  • ????????????????<value>*Bo</value>??
  • ????????????</list>??
  • ????????</property>??
  • ????????<property?name="interceptorNames">??
  • ????????????<list>??
  • ????????????<value>transactionInterceptor1</value>????
  • ???????????
  • ????????????<value>transactionInterceptor2</value>????????
  • ??????????????????
  • ????????????</list>??
  • ????????</property>??
  • ????</bean>??
  • ?的配置。

    ?

    ?

    看來~~~ spring 還是要注意bean的順序啊,哈哈哈。。。

    轉載于:https://www.cnblogs.com/langtianya/p/4962784.html

    總結

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

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