運用@Transactional,自己丟擲異常時不會回滾的原因
問題
使用spring的配置事物註解@Transactional,在測試的時候發現不起作用。
環境
配置檔案
- <beanid="studentMGDataSource"class="org.apache.commons.dbcp.BasicDataSource"
- destroy-method="close">
- <propertyname="driverClassName"value="${student_MG_jdbc.driver}"/>
-
<propertyname="url"value=
- <propertyname="username"value="${student_MG_jdbc.username}"/>
- <propertyname="password"value="${student_MG_jdbc.password}"/>
- <propertyname="initialSize"value="${student_MG_jdbc.initialSize}"/>
-
<propertyname="maxActive"value="${student_MG_jdbc.maxActive}"
- <propertyname="maxIdle"value="${student_MG_jdbc.maxIdle}"/>
- <propertyname="maxWait"value="${student_MG_jdbc.maxWait}"/>
- <propertyname="defaultAutoCommit"value="${student_MG_jdbc.defaultAutoCommit}"/>
- </bean>
-
<beanid="studentMGSqlSessionFactory"class="org.mybatis.spring.SqlSessionFactoryBean"
- <propertyname="configLocation"value="classpath:mybatis/mybatis-studentMG-config.xml"/>
- <propertyname="dataSource"ref="studentMGDataSource"/>
- </bean>
- <beanid="studentMGSqlSession"class="org.mybatis.spring.SqlSessionTemplate">
- <constructor-argindex="0"ref="studentMGSqlSessionFactory"/>
- </bean>
- <beanid="studentMGTxManager"
- class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <propertyname="dataSource"ref="studentMGDataSource"/>
- </bean>
- <tx:annotation-drivenproxy-target-class="true"transaction-manager="studentMGTxManager"/>
Java程式碼
- @Transactional(value="studentMGTxManager",rollbackFor=java.lang.Exception.class)
- publicvoid saveStudentDto(List<StudentDto> dtoList, String classId) {
- }
原因
資料庫使用的儲存引擎是MyISam,MyISam不支援事物,應該用InnoDB引擎
TIPS
@Transactional註解事務不起作用的解決
可能的原因:
1.資料庫引擎要支援事務
如果是MySQL,注意表要使用支援事務的引擎,比如innodb,如果是myisam,事務是不起作用的
2.是否開啟了對註解的解析
配置檔案必須加<tx:annotation-driven />,否則不解析@Transactional
假如讀者是在整合j2EE的三大框架式遇到這個問題,那應該就是下面這個問題:
我記得當時我遇到這個問題的時候,是因為資料庫的表,不支援事務!如果mysql不支援儲存引擎,它將以MyISAM表建立表,這是非事務性表。一般修改成InnoDB.
假如有興趣瞭解 mysql中 " engine=innodb " 以及 " engine=innodb 和engine=myisam的區別 ",可以讀讀這篇文章,或許對讀者有幫助:http://blog.sina.com.cn/s/blog_6ac4c6cb01018pb1.html
可使用下述語句之一檢查表的標型別:
SHOW TABLE STATUS LIKE 'tbl_name';
SHOW CREATE TABLE tbl_name;
使用下述語句,可檢查mysqld伺服器支援的儲存引擎:
SHOW ENGINES;
也可以使用下述語句,檢查與你感興趣的儲存引擎有關的變數值:
SHOW VARIABLES LIKE 'have_%';
例如,要想確定InnoDB儲存引擎是否可用,可檢查have_innodb變數的值。
二 、假如讀者不是上述情況,那請研讀下面這段:
--------------------------------------------------------------------------------------------------
近日測試用例,發現這樣一個現象:
在業務程式碼中,有如下兩種情況,比如:
throw new RuntimeException("xxxxxxxxxxxx"); 事務回滾
throw new Exception("xxxxxxxxxxxx"); 事務沒有回滾
自以為很瞭解事務,或許時間久遠的緣故,沒分析出來何故,遂查閱了下資料,寫下了如下的內容,供參考:
1).Spring的AOP即宣告式事務管理預設是針對unchecked exception回滾。也就是預設對RuntimeException()異常或是其子類進行事務回滾;checked異常,即Exception可try{}捕獲的不會回滾,如果使用try-catch捕獲丟擲的unchecked異常後沒有在catch塊中採用頁面硬編碼的方式使用spring api對事務做顯式的回滾,則事務不會回滾, “將異常捕獲,並且在catch塊中不對事務做顯式提交=生吞掉異常” ,要想捕獲非執行時異常則需要如下配置:
解決辦法:
1.在針對事務的類中丟擲RuntimeException異常,而不是丟擲Exception。
2.在txAdive中增加rollback-for,裡面寫自己的exception,例如自己寫的exception:
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" rollback-for="com.cn.untils.exception.XyzException"/>
</tx:attributes>
</tx:advice>
或者
定義不會滾的異常
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="update*" no-rollback-for="IOException"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
2).spring的事務邊界是在呼叫業務方法之前開始的,業務方法執行完畢之後來執行commit or rollback(Spring預設取決於是否丟擲runtime異常).
如果丟擲runtime exception 並在你的業務方法中沒有catch到的話,事務會回滾。
一般不需要在業務方法中catch異常,如果非要catch,在做完你想做的工作後(比如關閉檔案等)一定要丟擲runtime exception,否則spring會將你的操作commit,這樣就會產生髒資料.所以你的catch程式碼是畫蛇添足。
如:
try {
//bisiness logic code
} catch(Exception e) {
//handle the exception
}
由此可以推知,在spring中如果某個業務方法被一個 整個包裹起來,則這個業務方法也就等於脫離了spring事務的管理,因為沒有任何異常會從業務方法中丟擲!全被捕獲併吞掉,導致spring異常丟擲觸發事務回滾策略失效。
不過,如果在catch程式碼塊中採用頁面硬編碼的方式使用spring api對事務做顯式的回滾,這樣寫也未嘗不可。
3).基於註解的事務:
Transactional的異常控制,預設是Check Exception 不回滾,unCheck Exception回滾
如果配置了rollbackFor 和 noRollbackFor 且兩個都是用同樣的異常,那麼遇到該異常,還是回滾
rollbackFor 和noRollbackFor 配置也許不會含蓋所有異常,對於遺漏的按照Check Exception 不回滾,unCheck Exception回滾
在spring的配置檔案中,如果資料來源的defaultAutoCommit設定為True了,那麼方法中如果自己捕獲了異常,事務是不會回滾的,如果沒有自己捕獲異常則事務會回滾,如下例
比如配置檔案裡有這麼條記錄:
- <beanid="dataSource"class="xxx">
- <propertyname="xxx"value="xxx"/>
- <propertyname="xxx"value="xxx"/>
- ....
- <propertyname="defaultAutoCommit"value="true"/>
- </bean>
那麼現在有兩個情況
情況1:如果沒有在程式中手動捕獲異常
[java] view plain copy print?
- @Transactional(rollbackFor = { Exception.class })
- publicvoid test() throws Exception {
- doDbStuff1();
- doDbStuff2();//假如這個操作資料庫的方法會丟擲異常,現在方法doDbStuff1()對資料庫的操作 會回滾。
- }
情況2:如果在程式中自己捕獲了異常
[java] view plain copy print?
- @Transactional(rollbackFor = { Exception.class })
- publicvoid test() {
- try {
- doDbStuff1();
- doDbStuff2();//假如這個操作資料庫的方法會丟擲異常,現在方法doDbStuff1()對資料庫的操作 不會回滾。
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
現在如果我們需要手動捕獲異常,並且也希望拋異常的時候能回滾腫麼辦呢?
下面這樣寫就好了,手動回滾事務:
[java] view plain copy print?
- @Transactional(rollbackFor = { Exception.class })
- publicvoid test() {
- try {
- doDbStuff1();
- doDbStuff2();
- } catch (Exception e) {
- e.printStackTrace();
- TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();//就是這一句了,加上之後,如果doDbStuff2()拋了異常, //doDbStuff1()是會回滾的
- }
- }
相關推薦
運用@Transactional,自己丟擲異常時不會回滾的原因
問題 使用spring的配置事物註解@Transactional,在測試的時候發現不起作用。 環境 配置檔案 <beanid="studentMGDataSource"class="org.apache.common
程式碼丟擲異常後進行事務回滾的兩種方式(Spring @Transactional註解)
需求 在service層的某個方法中,在執行完一個對資料庫的寫方法後,丟擲異常,再執行另一個對資料庫的寫方法,虛擬碼如下: @Transactional public void func() { dao.write(pojo1); throw new Exception("異常"
java事務異常——Spring事務異常回滾,捕獲異常不丟擲就不會回滾
最近遇到了事務不回滾的情況,我還考慮說JPA的事務有bug? 我想多了....... 為了列印清楚日誌,很多方法我都加tyr catch,在catch中列印日誌。但是這邊情況來了,當這個方法異常時候 日誌是列印了,但是加的事務卻沒有回滾。 例: 類
十六、Spring事務異常回滾,捕獲異常不丟擲就不會回滾
最近遇到了事務不回滾的情況,我還考慮說JPA的事務有bug? 我想多了……. 為了列印清楚日誌,很多方法我都加tyr catch,在catch中列印日誌。但是這邊情況來了,當這個方法異常時候 日誌是列印了,但是加的事務卻沒有回滾。 例: 類似這樣的方法不會回滾 (一個方法出錯,另一個方
Spring事務異常回滾,捕獲異常不丟擲就不會回滾
最近遇到了事務不回滾的情況,我還考慮說JPA的事務有bug? 我想多了....... 為了列印清楚日誌,很多方法我都加tyr catch,在catch中列印日誌。但是這邊情況來了,當這個方法異常時候 日誌是列印了,但是加的事務卻沒有回滾。 例:
Java 原碼、反碼、補碼,自定義的異常類,手動丟擲異常。
1.byte 型佔一個位元組,正數按原碼儲存,負數按補碼儲存。第一位為符號符,“0”表示正數,“1”表示負數。 0000 0000表示 0 ,1000 0000 表示 -0,由於byte表示的範圍為256,+0,-0對應補碼都為0000000,所以補碼10000000沒有所為
Spring 事物丟擲Exception 異常時事物沒有回滾
Spring 宣告式事務 只針對 RuntimeException 異常丟擲時才會回滾事物,如果時Exception 丟擲時是不會回滾的。 如果想要讓exception 丟擲時也讓事物回滾 則可以在spring 配置檔案中新增 一個AOP 配置: <tx:adv
是返回錯誤碼,還是丟擲異常?說說我的選擇
昨晚翻了翻《 松本行弘的程式世界 》這本書,看到他對異常設計原則的講述,覺得頗為贊同。近期的面試,我有時也問類似的問題,但應聘者的回答大都不能令人滿意。有必要理一理,說說我是怎麼理解的,以及在程式設計實踐中如何做出合適的選擇。當然這只是一家之言,未必就是完全正確的。
Springboot中宣告事務@Transactional,為何有時候聲明瞭事務報異常資料卻不會回滾
@Transactional 這個註解相信大家都不陌生,這是事務的註解,什麼是事務,無非就是未保證資料一致性,當出現任何異常時候出現數據回滾 註解是是不需要寫提交事務的。 那麼,最近我發現,這個@Transactional的註解,並不是所有異常都可以進行資料回滾,他只有
Spring事務異常回滾,捕獲異常不拋出就不會回滾
actions .info time tpi detail ava ogg ren tool 最近遇到了事務不回滾的情況,我還考慮說JPA的事務有bug? 我想多了....... 為了打印清楚日誌,很多方法我都加tyr catch,在catch中打印日誌。但是這邊情
@Transactional 中使用 try catch之後不會回滾
採坑記錄: 使用spring的事務管理的時候,建議在service的try catch中丟擲自動異常,然後在controller層做統一的異常處理,再返回給檢視。也可以使用切面捕獲異常,返
問題描述: 在使用mybatis對資料庫執行更新操作時,parameterType為某個具體的bean,而bean中傳入的引數為null時,丟擲異常如下:
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.type.TypeException: Could not set parameters for mappin
關於Tomcat啟動專案時,控制檯丟擲各種異常,誤以為專案錯誤
1.當在eclipse啟動tomcat,初始化專案時,控制檯會列印啟動日誌:當出現 九月 19, 2017 3:07:35 下午 org.springframework.web.
stack 處理 pop時丟擲異常
leetcode 20 :https://leetcode.com/problems/valid-parentheses/description/ 如果 stack 為空時,pop()會 丟擲exception, 處理的方法如下: try { char top = st.pop(); if (!
【C#作業】學生成績新增並排序,錯誤則丟擲異常
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Cons
第四章App4_3,懂得了丟擲異常 throws Exception,read為讀取鍵盤輸入數,學會了switch迴圈
package 第四章; import java.io.EOFException; //filename:App4_3.javapublic class App4_3 //定義一個公共類App4_3{ public static void main(String[] args) throws Except
丟擲自定義的異常,異常處理中丟擲異常
你可以用raise語句來引發一個異常。異常/錯誤物件必須有一個名字,且它們應是Error或Exception類的子類 下面是一個引發異常的例子: class ShortInputException(Exception): ‘’‘自定義的異常類’’’ def init(self, le
synchronized重入後丟擲異常,鎖釋放了嗎
synchronized用於同步方法或者程式碼塊,使得多個執行緒在試圖併發執行同一個程式碼塊的時候,序列地執行。以達到執行緒安全的目的。 在多執行緒的時候是這樣的,但是對於單執行緒,是允許重入的,每重入一次,計數器加1,當退出程式碼塊時,計數器減1。 那正常退出時計數器減1,拋異常時計數器也是減1。那如果
java實現階乘的計算,丟擲異常不會,怎麼使用標號跳轉,需要幫解決一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
【求解答】service丟擲異常,為什麼controller捕捉不到呢?
RT,直接貼程式碼吧! 這個是我的service,service丟擲異常,controller沒有捕捉到,直接走進原始碼了。 //每日傳送次數 if (null != redisCacheManager.hget(KEY_CACHE_COUNT_SEND_VER