您好,登錄后才能下訂單哦!
下文我給大家簡單講講關于mysql環境RR隔離級別如何轉換成RC,大家之前了解過相關類似主題內容嗎?感興趣的話就一起來看看這篇文章吧,相信看完mysql環境RR隔離級別如何轉換成RC對大家多少有點幫助吧。
先了解RR(REPEATABLE-READ)和RC(READ-COMMITTED)的區別.
RR隔離級別增加了間隙鎖,避免了幻讀,并且阻止了不可重復讀,讓同一個事務里面的查詢和修改都是一致的.mysql默認的隔離級別就是RR.
雖然說RC隔離級別在同一個事務內會存在查詢出不同數據的現象,但是這些數據都必然是提交過的,是真實存進硬盤的數據.所以也不用過分擔憂,而且RC隔離級別反而降低了鎖粒度,也不是毫無用處.oracle和sql server默認的隔離級別類似RC.
所以說也不是說RC就絕對不好,要看場景來選擇,而這里只是簡介,不打算深入.
操作流程說明:因系統高并發下,存在多個會話可能同時更新同一條記錄的問題,但是值是一樣的.問題就在于事務里面存在RR隔離級別轉換成RC的問題,造成數據返回不正確,導致代碼返回錯誤,但是數據是準確的.
正常的RR事務
先看當前環境信息:
#當前的mysql版本 mysql> select @@version; +------------+ | @@version | +------------+ | 5.6.39-log | +------------+ 1 row in set (0.00 sec) #當前的隔離級別 mysql> select @@tx_isolation; +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+ 1 row in set (0.00 sec) #當前的binlog格式 mysql> show variables like 'binlog_format'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | binlog_format | MIXED | +---------------+-------+ 1 row in set (0.00 sec)
先看一個正常的事務:
#開啟事務 mysql> begin; Query OK, 0 rows affected (0.00 sec) | #開啟事務 mysql> begin; Query OK, 0 rows affected (0.00 sec) |
#當前記錄是一致的 mysql> select express_cost from m_order_sub where order_sub_no = 'O152022324482662671828'; +--------------+| express_cost | +--------------+ | 2000 | +--------------+ 1 row in set (0.02 sec) | #當前記錄是一致的 mysql> select express_cost from m_order_sub where order_sub_no = 'O152022324482662671828'; +--------------+| express_cost | +--------------+ | 2000 | +--------------+ 1 row in set (0.02 sec) |
#這邊先更新一條記錄 mysql> update m_order_sub set express_cost = 3000 where order_sub_no = 'O152022324482662671828'; Query OK, 1 row affected (0.01 sec)Rows matched: 1 Changed: 1 Warnings: 0 | |
#這邊后更新一條記錄,但是另一邊并沒有commit,所以這邊處于等待釋放鎖 update m_order_sub set express_cost = 3000 where order_sub_no = 'O152022324482662671828'; | |
#這邊再查詢一次,記錄成功修改 mysql> select express_cost from m_order_sub where order_sub_no = 'O152022324482662671828'; +--------------+| express_cost | +--------------+ | 3000 | +--------------+ 1 row in set (0.00 sec) | |
#提交事務 mysql> commit; Query OK, 0 rows affected (0.01 sec) | #然后鎖釋放后這邊的更新也執行完了,但是因為更新的值是一樣的,所以并沒有修改到記錄,Changed為0 Query OK, 0 rows affected (12.40 sec) Rows matched: 1 Changed: 0 Warnings: 0 |
#這邊再查詢一次,記錄成功修改,是最新數據 mysql> select express_cost from m_order_sub where order_sub_no = 'O152022324482662671828'; +--------------+| express_cost | +--------------+ | 3000 | +--------------+ 1 row in set (0.00 sec) | #這邊查詢結果是舊的,因為記錄并沒有被修改到,所以顯示的也是事務開始時的數據 mysql> select express_cost from m_order_sub where order_sub_no = 'O152022324482662671828'; +--------------+| express_cost | +--------------+ | 2000 | +--------------+ 1 row in set (0.00 sec) |
#提交并退出事務 mysql> commit; Query OK, 0 rows affected (0.13 sec) | |
#這時就顯示最新的數據了 mysql> select express_cost from m_order_sub where order_sub_no = 'O152022324482662671828'; +--------------+| express_cost | +--------------+ | 3000 | +--------------+ 1 row in set (0.00 sec) | |
這是一個正常的情況,因為記錄并沒有被修改到,所以顯示的也是事務開始時的數據,保證了RR級別的可重復讀特性.
問題現象
下面來看另一個不正常的情況,環境是和上面一致的,沒有改變,我們來直接看圖:
可以看到,執行方式和上面一致,右邊的事務等待了12秒后執行了,也就是左邊commit之后.但是,變成了不可重復讀,右邊事務里面沒有commit也可以看到最新提交的數據,甚是詭異.
解決方法
第一種方案:將隔離級別改成RC貌似是可以解決問題,但是解決的是左邊的問題,把可重復讀的特性改成了不可重復讀了而已.這樣兩邊都能查到已經提交的新數據.
#更改mysql全局隔離級別為RC set global tx_isolation = 'READ-COMMITTED'
改了之后,全局都變成了不可重復讀,并且沒有了間隙鎖,也正因為可以看到已經提交的新數據,所以上面正常的情況也會跟下面一致,但是不代表有問題,這本身就是RC隔離級別的特點.
然后有人說,這不是沒解決問題嘛,只是把問題全部改成一樣而已,好像是這樣.所以就有第二種方案.
第二種方案:把binlog格式改成ROW,不用改隔離級別,問題是真的解決了.
#把全局binlog格式改成ROW格式 set global binlog_format = 'ROW';
在上面看到原始的的binlog格式是MIXED混合模式,現在改成ROW模式,再試一遍.
好了,一切正常了,這就是RR的特性,可重復讀.
大家覺得mysql環境RR隔離級別如何轉換成RC這篇文章怎么樣,是否有所收獲。如果想要了解更多相關,可以繼續關注我們的行業資訊板塊。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。