摘要:引言對(duì)于追求數(shù)據(jù)強(qiáng)一致性的系統(tǒng),事務(wù)扮演者十分重要的角色最近在項(xiàng)目中遇到一個(gè)事務(wù)失效的問(wèn)題,在此分享給大家。情景回放問(wèn)題分析初步分析這是事務(wù)獲取鎖超時(shí)導(dǎo)致的錯(cuò)誤,奇怪的是拋出異常但是事務(wù)沒(méi)有回滾。唯一的解釋是事務(wù)失效了。
引言
對(duì)于追求數(shù)據(jù)強(qiáng)一致性的系統(tǒng),事務(wù)扮演者十分重要的角色.最近在項(xiàng)目中遇到一個(gè)事務(wù)失效的問(wèn)題,在此分享給大家。
情景回放### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction ; SQL []; Lock wait timeout exceeded; try restarting transaction; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:259) at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73) at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:73) at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446) at com.sun.proxy.$Proxy121.update(Unknown Source) at org.mybatis.spring.SqlSessionTemplate.update(SqlSessionTemplate.java:294) at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:62) at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59)問(wèn)題分析
初步分析這是事務(wù)獲取鎖超時(shí)導(dǎo)致的錯(cuò)誤,奇怪的是拋出異常但是事務(wù)沒(méi)有回滾?;蛟S你們說(shuō)MySQLTransactionRollbackException是檢查性異常(@Transactional默認(rèn)只捕獲非檢查性異常),但是項(xiàng)目添加了注解: @Transactional(rollbackFor = Exception.class)。唯一的解釋是——事務(wù)失效了。
ProductService.java /**********************************************************************/ public interface ProductService{ Integer getPrice(ProductInfo p); Integer compute(ProductInfo p); } /**********************************************************************/ ProductServiceImpl.java /**********************************************************************/ @Service public class ProductServiceImpl implements ProductService{ public Integer getPrice(ProductInfo p){ ... compute(p); ... } @Transactional(rollbackFor = Exception.class) public Integer compute(ProductInfo p){ //TestService的普通方法 try{ ... }catch(Exception e){ e.printStackTrace(); return -1; } } } /**********************************************************************/
初看這段代碼,沒(méi)啥毛病啊。噢,不對(duì),compute 方法內(nèi)部catch了異常,spring aop無(wú)法捕獲異常。如果需要捕獲異常,需要手動(dòng)回滾,于是compute方法修改如下:
@Transactional(rollbackFor = Exception.class) public Integer compute(ProductInfo p){ //TestService的普通方法 try{ ... }catch(Exception e){ e.printStackTrace(); TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();//手動(dòng)回滾事務(wù) return 0; } }
繼續(xù)運(yùn)行,結(jié)果發(fā)現(xiàn)事務(wù)還是未生效。通過(guò)查詢資料發(fā)現(xiàn),service方法直接調(diào)用了本類的一個(gè)方法(沒(méi)有通過(guò)接口調(diào)用),該方法上的事務(wù)將不會(huì)生效。
解決方案想啟用本類的普通方法的事務(wù),通過(guò)接口來(lái)調(diào)用該方法即可生效。如果先在方法內(nèi)部catch異常,需要添加TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();否則可以在外面捕獲這個(gè)異常。下面是在方法內(nèi)部捕獲異常的示例:
ProductService.java /**********************************************************************/ public interface ProductService{ Integer getPrice(ProductInfo p); Integer compute(ProductInfo p); } /**********************************************************************/ ProductServiceImpl.java /**********************************************************************/ @Service public class ProductServiceImpl implements ProductService{ @Autowired private ProductService productService; public Integer getPrice(ProductInfo p){ productService.compute(p); } @Transactional(rollbackFor = Exception.class) public Integer compute(ProductInfo p){ try{ ... }catch(Exception e){ e.printStackTrace(); TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); return 0; } } } /**********************************************************************/總結(jié)
Spring Transactional一直是RD的事務(wù)神器,但是如果用不好,反會(huì)傷了自己。下面總結(jié)@Transactional經(jīng)常遇到的幾個(gè)場(chǎng)景:
@Transactional 加于private方法, 無(wú)效 @Transactional 加于未加入接口的public方法, 再通過(guò)普通接口方法調(diào)用, 無(wú)效 @Transactional 加于接口方法, 無(wú)論下面調(diào)用的是private或public方法, 都有效 @Transactional 加于接口方法后, 被本類普通接口方法直接調(diào)用, 無(wú)效 @Transactional 加于接口方法后, 被本類普通接口方法通過(guò)接口調(diào)用, 有效 @Transactional 加于接口方法后, 被它類的接口方法調(diào)用, 有效 @Transactional 加于接口方法后, 被它類的私有方法調(diào)用后, 有效
Transactional是否生效, 僅取決于是否加載于接口方法, 并且是否通過(guò)接口方法調(diào)用(而不是本類調(diào)用)。
如果大家有更好的方法,歡迎加入討論!
參考博客:https://www.cnblogs.com/milto...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/69240.html
最近開始復(fù)習(xí)css一直在踩坑,今天分享一個(gè)inline-block 關(guān)于inline-block可能很多人都不熟悉,布局這方面很多人用的都是flex或者浮動(dòng),flex很強(qiáng)大毋庸置疑的可是關(guān)于兼容性就不是很讓人滿意,而浮動(dòng)雖然很兼容可是覺(jué)得清除浮動(dòng)就很麻煩,于此我在一些大型網(wǎng)站,例如我們的segmentfault的首頁(yè)導(dǎo)航展示用的布局就是inline-block,覺(jué)得inline-block可以擼一...
最近開始復(fù)習(xí)css一直在踩坑,今天分享一個(gè)inline-block 關(guān)于inline-block可能很多人都不熟悉,布局這方面很多人用的都是flex或者浮動(dòng),flex很強(qiáng)大毋庸置疑的可是關(guān)于兼容性就不是很讓人滿意,而浮動(dòng)雖然很兼容可是覺(jué)得清除浮動(dòng)就很麻煩,于此我在一些大型網(wǎng)站,例如我們的segmentfault的首頁(yè)導(dǎo)航展示用的布局就是inline-block,覺(jué)得inline-block可以擼一...
摘要:在頁(yè)面與傳值中我們經(jīng)常用到的方式,然后通過(guò)取的值今天在獲取值時(shí)怎么也取不到,后來(lái)發(fā)現(xiàn)對(duì)象有和屬性,而就在中,所以通過(guò)取到了正確的值。另外最好不要用駝峰命名如,這樣有時(shí)候也取不到值。 在頁(yè)面與js傳值中我們經(jīng)常用到data-id=1的方式,然后通過(guò)e.target.dataset.id取id的值今天在獲取值時(shí)怎么也取不到,后來(lái)發(fā)現(xiàn)e對(duì)象有currentTarget和target屬性,而d...
摘要:提示原因是對(duì)象中的值應(yīng)該為字符串正確的賦值打開方式應(yīng)該是不得不說(shuō)小程序中的坑真多,賦值類型還得是字符串 console提示:showModal:fail parameter error: parameter.content should be String instead of Undefined;原因是 Page({ data: { userInfo: {}, h...
摘要:在頁(yè)面與傳值中我們經(jīng)常用到的方式,然后通過(guò)取的值今天在獲取值時(shí)怎么也取不到,后來(lái)發(fā)現(xiàn)對(duì)象有和屬性,而就在中,所以通過(guò)取到了正確的值。另外最好不要用駝峰命名如,這樣有時(shí)候也取不到值。 在頁(yè)面與js傳值中我們經(jīng)常用到data-id=1的方式,然后通過(guò)e.target.dataset.id取id的值今天在獲取值時(shí)怎么也取不到,后來(lái)發(fā)現(xiàn)e對(duì)象有currentTarget和target屬性,而d...
閱讀 2425·2021-08-18 10:21
閱讀 2534·2019-08-30 13:45
閱讀 2165·2019-08-30 13:16
閱讀 2131·2019-08-30 12:52
閱讀 1376·2019-08-30 11:20
閱讀 2635·2019-08-29 13:47
閱讀 1633·2019-08-29 11:22
閱讀 2774·2019-08-26 12:11