Mysql RC/RR隔離原理和區別 不可重複讀和可重複讀

oktokeep發表於2024-06-08

Mysql RC/RR隔離原理和區別 不可重複讀和可重複讀

mysql四種隔離級別:
1.未提交讀(READ UNCOMMITED)髒讀
2.已提交讀 (READ COMMITED)簡稱(RC) 不可重複讀
3.可重複讀(REPEATABLE READ)簡稱(RR)
4.可序列化(SERIALIZABLE)
這個不用驗證了,所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾了,一般不用,效能特別低。

測試1 ,採用mysql 預設的隔離級別 RR ,啟動A、B兩個事務對比,阿拉伯數字遞增代表事務執行的時間順序

測試2 ,隔離級別設定為 RC ,啟動A、B兩個事務對比,阿拉伯數字遞增代表事務執行的時間順序

總結∶

可重複讀級別下(RR),開啟事務之後第一個select才會生成快照,而不是事務一開始就生成快照。 >> 在一個事務內 本事務未提交之前(外部事務已提交),查詢的仍然是上一次該資料快照。而不是最新資料。
讀已提交級別下(RC),每次select都會生成一個快照。 >> 在一個事務內 本事務未提交之前(外部事務已提交),查詢的是最新資料。

Oracle 預設使用READ COMMITTED(讀已提交)隔離級別
MySQL預設使用REPEATABLE(可重複讀)隔離級別

以下是測試步驟:
1.mysql客戶端SQLyog測試無效,需要透過 MySQL 8.0 Command Line Client客戶端來測試。
開啟2個MySQL 8.0 Command Line Client客戶端

2.資料庫預設事務是自動提交模式,檢視和修改提交模式
#檢視
SELECT @@autocommit;
#關閉自動提交
SET @@autocommit = 0;
#開啟自動提交
SET @@autocommit = 1;

-- 檢視當前會話的事務隔離級別
SELECT @@transaction_isolation; # REPEATABLE-READ
-- 檢視全域性的事務隔離級別
SELECT @@GLOBAL.transaction_isolation; # REPEATABLE-READ

修改隔離級別
READ UNCOMMITTED:允許事務讀取其他未提交的事務所做的修改。但是,會出現髒讀、不可重複讀和幻讀等問題。
READ COMMITTED:只允許事務讀取已經提交的事務所做的修改。在同一個事務內,對同一行資料的查詢可能返回不同的結果。
REPEATABLE READ:事務執行期間,保證多次讀取同一資料結果一致。但是,可能出現幻讀問題。
SERIALIZABLE:最高階別的隔離級別,完全序列化事務執行。確保每個事務對資料庫的讀寫操作是相互獨立的。

概念:
併發事務會出現更新丟失、髒讀、不可重複讀,幻讀。
更新丟失:當兩個或多個事務更新同一行記錄,會產生更新丟失現象。回滾覆蓋,一個事務回滾操作,把其他事務已提交的資料給覆蓋了;提交覆蓋,一個事務提交操作,把其他事務已提交的資料給覆蓋了
髒讀:一個事務讀取到了另一個事務修改但未提交的資料
不可重複讀:一個事務讀到了另一個事務已經提交的update資料,導致多次查詢結果不一致
幻讀:在同一個事務中,前後兩次查詢同一個範圍的資料時,發現有新的資料插入,導致結果集不一致的情況。


SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;

##測試發現需要修改全域性才生效
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;


手動控制事務
開啟事務:BEGIN; 和 START TRANSACTION; 在功能上是等價的。它們都會開始一個新的事務。
提交事務:COMMIT;
回滾事務:ROLLBACK;

#建立測試表
CREATE TABLE `isolation_level_test` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) DEFAULT NULL,
`age` INT(11) DEFAULT NULL,
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

##初始化1條記錄
INSERT INTO `isolation_level_test` (`id`, `name`, `age`, `create_time`) VALUES (1, 'forlan3', 11, '2024-05-29 13:45:11'); # 5


# 對應上面的圖示
#視窗1
BEGIN; # 1
SELECT * FROM isolation_level_test; # 3
SELECT * FROM isolation_level_test; # 7
COMMIT; # 8
SELECT * FROM isolation_level_test; # 9

#視窗2
BEGIN; # 2
SELECT * FROM isolation_level_test; # 4
INSERT INTO `isolation_level_test` (`id`, `name`, `age`, `create_time`) VALUES (11, 'forlan3', 12, '2024-05-29 13:45:11'); # 5
COMMIT; # 5
SELECT * FROM isolation_level_test; # 6

## 擴充套件 SERIALIZABLE 所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾了。
視窗1 在查詢的時候,如果視窗2 新增的資料,但是沒有提交,視窗1就卡在那裡,查詢不出結果。只有等視窗2提交或回滾,視窗1才可以查詢出來結果。

相關文章