事務註解(@Transactional)引起的資料覆蓋故障
最近組織團隊內技術培訓,劉聰為分享的一個跟事務和寫資料庫相關的case(bug)很有代表性。用事務,要小心!
一、故障現象
車輛交付履約流程上兩個節點(工程專案)A和B, A修改一條資料記錄item(工單),然後發訊息給B,B也會對item進行修改。
故障現象,有時候(不是必現)感覺A沒有成功修改item這條資料,而日誌顯示A修改成功了資料item!
看一下具體程式碼實現。下圖是工程A程式碼,3個紅框依次動作。
1、開啟事務
2、修改工單記錄item
3、向下遊節點傳送mq訊息
下圖是下游消費mq訊息的節點B,紅框表示採用JPA技術修改資料記錄item
二、原因分析
這個過程總共經歷5個步驟,見下圖
1、節點A開啟一個事務,修改資料表中某條資料item
2、A向B傳送mq訊息,再做些其他事情,提交事務
3、節點B,消費mq訊息
4、節點B讀出資料item
5、節點B在記憶體中修改資料item某些欄位,寫回資料庫
注意到第1、2步驟是在一個事務中。存在一種可能,B節點收到mq訊息,執行第4步驟,讀取item資料後,步驟1、2的事務才完成提交。由於資料庫事務隔離級別,這種情況下,第4步驟讀到的資料並不是A節點在第1步寫的,已經讀到髒資料了。當第5步寫回資料的時候,就可能造成老資料覆蓋A寫的新資料。
這裡有兩個細分場景
1、第1步、第5步修改同一個欄位。這種情況,第4步驟讀到髒資料
2、第1步、第5步修改不同欄位。第4步讀到col2欄位的oldvalue,第5步目的是修改col3的值,但是採用jpa或者mybatis的一些預設寫法,會把col2的oldvalue更新回資料庫。
一般的ORMapping框架利用一個vo物件寫資料庫記錄,沒有修改的欄位不會更新(程式碼裡並沒有改col2的值),但是第4步讀取資料後,第1步對資料item進行了修改。這樣預設的寫庫方法,會check記錄的變化,然後把col2欄位的值更新。這樣就出現了舊值覆蓋新值的問題。
三、解決辦法
1、考慮到實施成本,如果修改不同的欄位,不存在競爭關係。只需要在第5步寫庫的環節指定更新欄位就能快速解決這個問題。事實上,生產環境下也是選擇的這個方案臨時修復。
2、解決辦法1顯然不夠優秀。更好的做法,把第2步發mq訊息從事務中拆出來,等第1步操作commit後在發mq訊息。這個辦法涉及到一些邏輯的梳理(業務程式碼裡會有不少的if……else),程式碼的改動。這樣處理仍然不夠完美,第1步執行完了,第2步失敗了怎麼辦?在這裡可能需要一些額外的程式碼工作保證第2步執行成功。
3、如果業務壓力不大,也可以考慮從資料庫的事務隔離級別方面入手來解決這個問題。
4、業務上,第1步到第5步如果需要強一致,瞭解一下分散式事務
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31556438/viewspace-2648709/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 【Spring註解】事務註解@TransactionalSpring
- JPA的事務註解@Transactional使用總結
- 關於事務回滾註解@Transactional
- @Transactional註解管理事務和手動提交事務
- Spring非同步Async和事務Transactional註解Spring非同步
- Spring事務的介紹,以及基於註解@Transactional的宣告式事務Spring
- spring,mybatis事務管理配置與@Transactional註解使用[轉]SpringMyBatis
- @Transactional 註解下,事務失效的多種場景
- 《四 spring原始碼》spring的事務註解@Transactional 原理分析Spring原始碼
- spring事物配置,宣告式事務管理和基於@Transactional註解的使用Spring
- 為什麼阿里規定需要在事務註解@Transactional中指定rollbackFor?阿里
- Java開啟事務(@Transactional)Java
- @Transactional spring 配置事務 注意事項Spring
- 四、事務拓撲(Transactional Topolgoy)Go
- SpringBoot事務相關備忘(方法新增@Transactional註解,以及SQL語句(SQLServer資料庫)新增SET NOCOUNT ON)Spring BootSQLServer資料庫
- 內部呼叫@Transactional 註解的方法
- Java方法覆蓋和變數覆蓋的區別詳解Java變數
- sqoop export 資料覆蓋更新OOPExport
- Spring宣告式事務@Transactional使用Spring
- 11.日誌和事務@Transactional
- Spring中@Transactional事務使用陷阱Spring
- 一次資料檔案映象丟失引起的故障解決
- Spring @Transactional註解淺談Spring
- logminer恢復誤覆蓋更新的資料
- @Transactional開啟事務導致AbstractRoutingDataSource動態資料來源無法切換的解決方案
- Spring @Transactional 宣告式事務揭祕Spring
- 企業WiFi覆蓋,解決覆蓋四大難題WiFi
- ORACLE資料庫事務處理和故障恢復Oracle資料庫
- Spring中的AOP,以及宣告式事務 @Transactional無法攔截事務Spring
- Spring+Mybatis事務@Transactional註解timeout屬性作用過程原始碼淺層DebugSpringMyBatis原始碼
- 百貨wifi無線覆蓋增值服務解決方案WiFi
- 基於註解的Spring多資料來源配置和使用(非事務)Spring
- 分散式資料庫事務故障恢復的原理與實踐分散式資料庫
- 事務槽引起的 ORA-600 事件事件
- open session in view引起的事務問題SessionView
- 教你兩種資料庫覆蓋式資料匯入方法資料庫
- goldengate中長事務引起的問題Go
- 工作 6 年,@Transactional 註解用的一塌糊塗