最近在看mysql相關的書籍.實驗了一些內容.分享一下,主要是關於事務隔離級別(read-committed和repeatable-read)和鎖相關的.
很多網上文章上都能搜尋到 read-committed可以防止髒資料.但是不能防止 不可重複讀.
而repeatable-read可以防止 不可重複讀.但是不能防止幻讀.
現在我想分享下具體是怎麼操作的.
read-committed和repeatable-read的區別到底是什麼?
我覺得在 不可重複讀 這個問題上並沒有涉及鎖的問題.而是涉及一致性非鎖定讀的問題
假設有一張user,主鍵id int, name varchar, i varchar.
在i這一列上有索引,非唯一.
資料如下:
id name i
1 v1 i1
5 v5 i5
9 v9 i9
所有session的 autocommit=0 不會自動提交.
session a:
update user set name = 'v5-new' where id = 5;
這個時候鎖定了id=5這一列.沒有commit
session b:
select name from user where id = 5
查詢出來是v5.這是因為rr和rc都不會讀到髒資料
然後session a:
commited;
這個時候行最新的name已經是v5-new了
session b:
select name from user where id = 5
這個時候的select就有區別了.
rc讀出來是v5-new, rr仍然是v5
但是要注意的是session b在這裡始終都只是一般的select,所以沒有加鎖.所以這裡不可重複和鎖我覺得沒有關係(但是和session a在記錄上加的x鎖有點關係,因為這條記錄被鎖定了).
那為什麼2種隔離級別會有區別呢? 因為一致性非鎖定讀的原因
session b第一次讀取發現記錄id=5被鎖定(有x鎖).那讀的時候就會從undo日誌裡找到原始的值.也就是v5.
第二次讀的時候rc和rr有區別.rc因為session a已經committed,會讀最新的行資料,也就是v5-new
而rr仍然會讀取之前讀到的那個snap-shot版本,也就是v5.所以會有區別..
rr模式下加上鎖可以解決幻讀的問題(還原之前的資料).
實驗如下:
session a:
update user set name = 'v55' where i = 'i5';
沒有committed
session b:
insert into user values(6, 'v6', 'i5');
這個時候如果b可以committed,那就會產生幻讀的問題.因為a明明修改了所有i=i5的資料.
但是卻沒有修改b插入的那條.
但是實際上session b執行這個insert的時候回等待.
因為a鎖住了i = i5的資料.所以b是插入不了的.
那如果b執行的是
insert into user values(6, 'v6', 'i6'); 可以嗎?
事實上也會等待.因為a會鎖定i=i5的資料和它到上下兩條相鄰資料的區間.
也就是說 i1-i5, i5, i5-i9的資料都被鎖住了.都是不能插入的.
insert into user values(10, 'v10', 'ia');
這條記錄就可以插入.因為ia在i9之後(字母大於數字).
mysql對主鍵會鎖單條記錄.但是對非唯一的一般的索引,會鎖單條記錄加上上下範圍
mysql鎖問題 事務隔離級別
相對其他資料庫而言,mysql的鎖機制比較簡單,其最顯著的特點是不同的儲存引擎支援不同的鎖機制。innodb最大的特點就是一是支援事務 transaction 二是採用了行級鎖。所以我們先來引申一下事務和事務隔離級別的知識。1.1 事務以及acid屬性 事務是由一組sql語句組成的邏輯處理單元,事務...
mysql隔離級別 MySQL 事務隔離級別
mysql innodb所提供的事務滿足acid的要求,事務是通過事務日誌中的redo log和undo log來實現原子性 undo log 一致性 undo log 永續性 redo log 事務通過鎖機制實現隔離性。1 事務隔離級別與實現read uncommitted 讀未提交 read c...
MySQL的事務隔離級別和鎖
mysql的事務隔離級別 read uncommitted 讀未提交資料 read committed 讀已提交資料 repeatable read 可重讀 serializable 可序列化 檢視mysql的事務隔離級別 預設 全域性和會話事務隔離級別 select tx isolation se...