事務註解(@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
- 關於事務回滾註解@Transactional
- Spring非同步Async和事務Transactional註解Spring非同步
- @Transactional註解管理事務和手動提交事務
- Spring事務的介紹,以及基於註解@Transactional的宣告式事務Spring
- 《四 spring原始碼》spring的事務註解@Transactional 原理分析Spring原始碼
- @Transactional 註解下,事務失效的多種場景
- spring事物配置,宣告式事務管理和基於@Transactional註解的使用Spring
- 為什麼阿里規定需要在事務註解@Transactional中指定rollbackFor?阿里
- SpringBoot事務相關備忘(方法新增@Transactional註解,以及SQL語句(SQLServer資料庫)新增SET NOCOUNT ON)Spring BootSQLServer資料庫
- Java開啟事務(@Transactional)Java
- Spring @Transactional註解淺談Spring
- 內部呼叫@Transactional 註解的方法
- Spring+Mybatis事務@Transactional註解timeout屬性作用過程原始碼淺層DebugSpringMyBatis原始碼
- Spring中@Transactional事務使用陷阱Spring
- Spring宣告式事務@Transactional使用Spring
- @Transactional開啟事務導致AbstractRoutingDataSource動態資料來源無法切換的解決方案
- 11.日誌和事務@Transactional
- Spring @Transactional 宣告式事務揭祕Spring
- 企業WiFi覆蓋,解決覆蓋四大難題WiFi
- 分散式資料庫事務故障恢復的原理與實踐分散式資料庫
- 事務槽引起的 ORA-600 事件事件
- 百貨wifi無線覆蓋增值服務解決方案WiFi
- 教你兩種資料庫覆蓋式資料匯入方法資料庫
- 工作 6 年,@Transactional 註解用的一塌糊塗
- Spring Boot註解@Transactional結合實際例子講解Spring Boot
- 室外無線覆蓋解決方案
- 如何避免舊請求的資料覆蓋掉最新請求
- 矩形覆蓋
- 資料庫系列:覆蓋索引和規避回表資料庫索引
- 基於程式覆蓋資訊的資料庫核心問題定位工具資料庫
- 資料庫事務以及事務的四個特性資料庫
- 在做服務端程式碼覆蓋率或者準備做程式碼覆蓋率的兄弟們,來聊聊???服務端
- MyBatis 事務管理解析:顛覆你心中對事務的理解!MyBatis
- 資料庫事務的特徵資料庫特徵
- 室外無線AP覆蓋解決方案
- rest_framework django 簡單使用(資料庫建立資料, 覆蓋資料, 其他的大同小異)RESTFrameworkDjango資料庫
- istanbul 繞過 window 變數儲存覆蓋率資料變數