REPEATABLE-READ隔離級別 事務中無法讀到其它事務提交了的最新數據

前言:

業務要求一個簡單的併發控制,使得一條數據只被確認一次,我的方案是 悲觀鎖,就是在事務中先對數據行加鎖(MySQL InnoDB 行鎖基於索引),判斷是否已經確認過,未確認的情況下確認,已確認則事務提交釋放鎖。代碼寫完,結果發現未生效,就開始了滿腦子問號的排查過程。

業務代碼結構如下:

        //不要這麼做 
        //一沒對異常進行處理 
        //二事務的範圍太大包含很多不需要在事務中的代碼
        @Transactional
        public void dangerConfirm(ConfirmDangerRequest request) throws CommonException {
            String zhiXinBianHao = request.getZhiXinBianHao();
            //此處方法中包含一次查詢操作  查詢表 A數據
            CodeWxid codeWxid = hisDaoService.getCode(request.getConfirmUserId());
            if (codeWxid == null || codeWxid.getWxId() == null){
                throw new CommonException("工號或企業微信id有問題", ResultStatusCode.INVALID_CAPTCHA);
            }
            //在此行打斷點先阻塞
            //悲觀鎖  鎖表B中的一行數據  mybatis
            String lock = someMapper.lock("AED5ADC3C67E4A89AB7161DA84DC1FC1");
            System.out.println(lock);
            //用JPA查同一條數據 偷懶 表B
            BaseInfo baseInfo = baseInfoRepository.findByZhiXinBianHao("AED5ADC3C67E4A89AB7161DA84DC1FC1");
            //用mybatis查詢同一行的某個字段  表B
            String te = someMapper.te("AED5ADC3C67E4A89AB7161DA84DC1FC1");

情況描述:

在MySQL命令行直接開事務,鎖同一行,此時上文代碼斷點往下執行會等待鎖的釋放,正常。在命令行事務中更新數據中的某個字段,後提交。此時,調試代碼獲取到鎖,向下執行時 發現問題:最後兩行,均未查出命令行已經提交的字段的值,即 無法讀到其它事務已經提交的數據。這和我所掌握的知識不符。

分析:

數據庫MySQL的隔離級別時 RR,不會出現髒讀和不可重複讀。問題是現在其它事務提交的都讀不到,但是數據庫軟件是可以查到的。沒辦法了,排除法,把所有與事務無關的註釋掉,一執行,好了。。。。。。可以正常查到其它事務已提交的數據。

那麼,自然地就定位到 下面這行的問題

//此處方法中包含一次查詢操作  查詢表 A數據
CodeWxid codeWxid = hisDaoService.getCode(request.getConfirmUserId());

加上上面這行,又不行了。。。。。除了悲觀鎖那行外,後面又讀不到其它事務提交的數據了。。

發現了這個現象,下面就開始做實驗(隔離級別爲 REPEATABLE-READ):

起兩個MySQL命令行客戶端A、B,兩邊都 set autocommit = 0; start transaction;

實驗一:A更新一條數據行 id = 1,值更新爲 99,此時A不提交,B是查不到新值99的。A提交,B直接查詢此條數據,可以查到值99。注意,在此之前B從未執行過查詢操作。

實驗一:A更新一條數據行 id = 1,值更新爲 99,此時A不提交,B是查不到新值99的。A提交,B先任意執行一條查詢,再查詢此條id=1的數據,就不可以查到值99,查到的是之前的舊值。

這好像很符合 REPEATABLE-READ隔離級別的定義

使用 set @@session.tx_isolation='read-committed'; 將AB會話的隔離級別調整爲 read-committed。發現:B事務任何情況下都可以讀到A事務剛提交的最新數據。

總結:

MySQL默認的隔離級別爲 REPEATABLE-READ,這個隔離級別使得 前後讀取同一條的值是相同的,不會受其它事務的影響,除非它自己改變的。

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章