MySQL事務隔離級別以及實現原理
阿新 • • 發佈:2019-01-26
一、事務完整性問題
髒讀:可以讀取其他事務未提交的資料,如果該事務回滾,則資料為錯誤資料。
不可重複讀:A事務檢視,B事務修改提交,A事務再次檢視,資料不一樣。
幻讀:幻讀與不可重複讀相似,但不可重複讀重點在於update和delete,幻讀重點在於insert
t Session A Session B | | START TRANSACTION; START TRANSACTION; | | SELECT * FROM t_bitfly; | empty set | INSERT INTO t_bitfly | VALUES (1, 'a'); | | SELECT * FROM t_bitfly; | empty set | COMMIT; | | SELECT * FROM t_bitfly; | empty set | | INSERT INTO t_bitfly VALUES (1, 'a'); | ERROR 1062 (23000): | Duplicate entry '1' for key 1 v (???剛剛明明告訴我沒有這條記錄的)
t Session A Session B | | START TRANSACTION; START TRANSACTION; | | SELECT * FROM t_bitfly; | +------+-------+ | | id | value | | +------+-------+ | | 1 | a | | +------+-------+ | INSERT INTO t_bitfly | VALUES (2, 'b'); | | SELECT * FROM t_bitfly; | +------+-------+ | | id | value | | +------+-------+ | | 1 | a | | +------+-------+ | COMMIT; | | SELECT * FROM t_bitfly; | +------+-------+ | | id | value | | +------+-------+ | | 1 | a | | +------+-------+ | | UPDATE t_bitfly SET value='z'; | Rows matched: 2 Changed: 2 Warnings: 0 | (怎麼多出來一行) | | SELECT * FROM t_bitfly; | +------+-------+ | | id | value | | +------+-------+ | | 1 | z | | | 2 | z | | +------+-------+ |
二、事務隔離級別
1. 讀未提交(Read Uncommitted)
原理:任何操作都不加鎖
2. 讀提交(Read Commit)
原理:讀操作不加鎖,寫操作加鎖。讀被加鎖的資料時,讀事務每次都讀undo log中的最近版本,因此可能對同一資料讀到不同的版本(不可重複讀),但能保證每次都讀到最新的資料。3. 可重複讀(Reapable Read)
原理:第一次讀資料的時候就將資料加行鎖(共享鎖),使其他事務不能修改當前資料,即可實現可重複讀。但是不能鎖住insert進來的新的資料,當前事務讀取或者修改的同時,另一個事務還是可以insert提交,造成幻讀。4. 序列化(Serializable)
原理:鎖表,讀鎖和寫鎖阻塞。
三、InnoDB事務相關概念
● redo log
MySQL在開啟事務時,會將執行的SQL儲存到指定的log檔案,即redo log。當MySQL執行recovery時執行redo log裡的SQL操作即可。redo log不會被立即寫入磁碟,會先寫入redo buffer;當客戶端執行commit時,redo buffer的內容會視情況存入磁碟。
● undo log
與redo log相反,undo log是為了回滾事務而寫的日誌,具體內容就是copy事務開始前的資料(行)到undo buffer。
與redo buffer一樣,undo buffer也是環形緩衝,當緩衝滿的時候buffer內容會被重新整理到磁碟。
與redo log不同的是,undo log沒有獨立的磁碟檔案,所有的undo log均被存在主ibd資料檔案中(表空間)。