作者:溫安適
來源:https://my.oschina.net/floor/blog/4784609
問題
一個忙(mo)碌(yu)的下午,小航同學,突然大罵一聲,“TM ,見鬼了,version沒變,更新就是不成功”,
我看他,滿頭大汗,雙手握拳,面目猙獰,似乎又要發作,趕緊說:“不成功沒關系啊,重試就好,樂觀鎖一般是要重試的”
他略帶鄙視的說道:代碼有重試了邏輯,我還加日志了,結果發現version沒變,就是更新不成功,
作為對技術小有追求的人,他怎么一說,立刻引起了我的好奇,隨后誠懇的說道,我能看看代碼嗎?
小航,一句不發,雙手卻筆畫了個請的姿勢,
我仔細端詳,代碼大致邏輯如下:
@Transactional(timeout = 36000, rollbackFor = Throwable.class)
public void updateGoodNum(String id,Integer num)
throws Exception {
//1. select num as dbnum,version as dbversion from t where id=#{id}
//2. update t set num=dbnum-num,version =dbversion +1
// where id=#{id} and version =dbversion ;
// 如果更新失敗,重試1,2部總共3回
}
我輕嘆了口氣,在mysql連接工具執行了,如下陳述句,將截圖發給小航后,

擺出個大師的模樣說道:咱們測驗環境隔離級別是RR(REPEATABLE-READ),在一個事務中重試是不行的!
小航難為情的說的:大哥,什么是隔離級別啊? 為什么不行啊? 怎么改呢?
隔離級別
| 隔離級別 | 說明 |
|---|---|
| READ UNCOMMITTED | 未提交讀,會造成臟讀,違反持久性D |
| READ COMMITTED | 讀已提交資料, 會造成幻讀 違反一致性C |
| REPEATABLE READ(RR) | 可重復讀,默認隔離級別,事務中的select 陳述句會讀取事務開始前的快照,當然也能讀到本事務的更新內容 |
| SERIALIZABLE | 不會使用mysql的mvcc機制,而是在每一個select請求下獲得讀鎖,在每一個update操作下嘗試獲得寫鎖 |
update操作是讀取當前值,
那在RR隔離級別下,為什么在一個事務中重試是不行的呢?
表格模擬,為什么不行?
| 開始事務前 | 表t對應id=1的,version=1 | |
|---|---|---|
| 事務Abegin | 事務Bbegin | |
| 1 | select version from t where id=1;-- 得到version=1 | update t set version=2 where id=1;commit; |
| 2 | update t set XX where id=1 and version=1;// 更新失敗,update讀取當前,version=2 | |
| 3 | select version from t where id=1;// 得到version=1 | |
| 4 | commit |
注意:事務中的select 是讀快照,update是讀當前,
簡單說,就去其他事務,已經將version修改了2,事務A看到的還是事務開始前的值
也就是version為1.
解決方式
RR隔離級別下,將重試移到事務外. 即每次重試重新開一個事務
概要邏輯如下
/// 如果更新失敗,重試updateGoodNum總共3回
public AFacadeImpl{
@Autowired
AService aservice;
public void updateGoodsNum(){
int i = 0;
while(!aservice.updateGoodNum(id,num) && i++ < 3);
}
}
public AServiceimpl implement AService{
@Transactional(timeout = 36000, rollbackFor = Throwable.class)
public boolean updateGoodNum(String id,Integer num)
throws Exception {
//1. select num as dbnum,version as dbversion from t where id=#{id}
//2. update t set num=dbnum-num,version =dbversion +1
// where id=#{id} and version =dbversion ;
/
}
}
近期熱文推薦:
1.1,000+ 道 Java面試題及答案整理(2021最新版)
2.終于靠開源專案弄到 IntelliJ IDEA 激活碼了,真香!
3.阿里 Mock 工具正式開源,干掉市面上所有 Mock 工具!
4.Spring Cloud 2020.0.0 正式發布,全新顛覆性版本!
5.《Java開發手冊(嵩山版)》最新發布,速速下載!
覺得不錯,別忘了隨手點贊+轉發哦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/291402.html
標籤:其他
