Mysql鎖模塊

1、InnoDB和MyISAM引擎鎖方面的區別

1. InnoDB

InnoDB默認支持行級鎖,也支持表級鎖。mysql

InnoDB在sql中用到索引時使用的時行級鎖;沒有用到索引的時候,或者索引不明確時(>,<,like)使用的是表級鎖。算法

InnoDB(增刪改)時會自動加鎖,select操做時不加鎖(默認是用的非鎖定讀),須要顯示加寫鎖(for update)和讀所(lock in share mode)sql


2. MyISAN

MyISAM默認支持表級鎖,不支持行級鎖。數據庫

MyISAM(增刪改查)都會自動上鎖。併發

MyISAM不支持事務mvc

 

2、數據庫事務四大特效

1.原子性

2.隔離性

3.一致性

4.持久性

 

3、Mysql事務隔離級別,以及各級別下的併發訪問問題

更新丟失--mysql全部事務隔離級別在數據庫層面上都可避免函數

髒讀--READ COMMITTED事務隔離級別以上可避免高併發

不可重複讀--REPEATABLE READ事務隔離級別以上可避免性能

幻讀--SERIALIZABLE事務隔離級別可避免spa

 

1. READ UNCOMMITTED (未提交讀)

事務中的修改,即便沒有提交,對其餘事務也都是可見的。

事務能夠讀取未提交的數據,出現髒讀(dirty read)(讀取別的事務還未提交的數據)

 

2. READ COMMITTED (提交讀)

一個事務從開始直到提交前,所作的任何修改對其餘事務都是不可見的;也叫不可重複讀(nonrepeatable read),由於兩次相同的查詢可能會獲得不同的結果。

大多數數據庫系統(Sql Server , Oracle)的默認隔離級別 READ COMMITTED(msyql不是)。

出現不可重複讀問題: 在當前事務中屢次讀取同一數據結果不一致(側重與同一數據的修改)

A: start transaction .   B: start transaction
A: select 100;     
  B: update 100 + 100
A: select  100 ;     
  B: commit;
A: select 200;  
A: commit;  

 

3. REPEATABLE READ (可重複讀)

mysql默認事務隔離級別

InnoDB和XtraDB引擎經過多版本併發控制(MVCC, Multiversion Concurrency Control)解決了幻讀

解決了不可重複讀;

A: start transaction .   B: start transaction
A: select 100;     
  B: update 100 + 100
A: select  100 ;     
  B: commit;
A: select 100;  
A: update + 100  
A: select 300  

出現幻讀(側重於新增和刪除),當某個事務在讀取某個範圍內數據時,另一個事務又在該範圍內插入了新的記錄,當以前的事務再次讀取該範圍內記錄時,會產生幻行。

repeatable read隔離級別下

A: start transaction .   B: start transaction
A: select  ... lock in share mode(當前讀);     
 

B: insert into .. value()

A使用的是當前讀,阻塞沒法插入(避免了幻讀)

A: commit

 
A: start transaction .   B: start transaction

A: select  10條 (當前讀)

 
  B: insert into ...value()
  B: commit
A: update ...(修改了11條)  
A: commit  

select 某記錄是否存在,不存在,準備插入此記錄,但執行 insert 時發現此記錄已存在,沒法插入,此時就發生了幻讀。 

A: start transaction .   B: start transaction

A: select  where id = 1;   empty

 
  B: insert into value(1)
  B: commit
A: insert into value(1);  error  
A: select where id = 1; empty  
A: commit  

read committed隔離級別下 

A: start transaction .   B: start transaction
A: select  ... lock in share mode;(3行)   
 

B: insert into .. value()(插入1行)

(實際狀況:read committed 自動變爲repeatable read 級別,阻塞沒法插入)

  B: commit;
A: update (更新了4行)  
A: commit  

4. SERIALIZABLE  (可串行化)

SERIALIZABLE 最高的隔離級別;

經過強制事務串行執行,避免了幻讀問題;SERIALIZABLE會在讀取的每一行數據上都加鎖,因此可能致使大量的超時和鎖爭用問題。

實際應用中不多用到這種隔離級別,只有在很是須要確保數據一致性並且接受沒有併發的狀況下,才考慮採用該級別

 

 

4、死鎖

死鎖:指兩個或者多個事務在同一資源上相互佔有,並請求對方佔用的資源

InnoDB目前處理死鎖的方法是:將持有最少行級鎖的事務進行會滾

 

5、RC、RR級別下的InnoDB的非阻塞讀(快照讀)如何實現

數據行裏隱藏字段的DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID字段

DB_TRX_ID:該字段用來標識最近一次對本行記錄作修改(update ,delete)(最後一次修改本行記錄的事務id)

DB_ROLL_PTR: 回滾指針

DB_ROW_ID: 隱示建立的自增主鍵字段

undo日誌:對記錄變動操做時產生undo記錄,存儲的是老版數據,當一個久的事務須要讀取事務時,爲了可以讀取老版本的數據,須要順着undo鏈找到其知足可見性的記錄,分爲insert(事務回滾時須要,並在事務提交後當即丟棄)和update undo log

insert undo log: 事務回滾時須要,並在事務提交後當即丟棄

update undo log:事務對記錄進行delete 或update操做時產生的undo log, 在事務回滾時和快照讀時須要

1. 鎖住該行日誌,

2. 並將數據拷貝一份到undo log,

3. 修改當前行的值,

4. 填寫事務id(DB_TRX_ID),

5. 使用回滾指針(DB_ROLL_PTR)指向undo log中修改前的行

read view :作可見性判斷,當執行快照讀select時,會針對查詢的數據建立一個read view,來決定當前事務能看到的是哪一個版本的數據(多是最新數據,也可能只容許看undo log某個版本的數據),read view遵循一個可見性算法,將要修改的數據DB_TRX_ID取出來與系統其餘活躍事務id作對比,若是大於或等於這些事務id,就經過DB_ROLL_PTR指針去取出undo log上一層的DB_TRX_ID直到小於這些活躍事務id爲止,保證了獲取到的數據版本是當前可見的最穩定的版本。

mysql源碼,保存活動事務的地方,m_low_limit_id(活動事務最大id),m_up_imit_id(活動事務最小id)。start transtaction,越新開啓的事務id越多,遞增

 

6、InnoDB可重複讀隔離級別下如何避免幻讀

表象:快照讀(非阻塞讀)--僞MVCC,(並非多版本共存,undo log是串行化的結果),讀不加鎖,讀寫不衝突

內在:next-key鎖(行鎖+gap鎖)

        (不管是當前讀仍是快照讀,在innodb的RR的事務隔離級別下均可以免幻讀。在快照讀的狀況下,innodb經過mvcc來避免幻讀;在當前讀的狀況下,innodb經過next-key鎖來避免幻讀)

 

當前讀:加了鎖的增刪改查, (不論是共享鎖仍是排他鎖均爲當前讀,insert, delete, update, select ... for update, select ... lock in share mode)

            讀取的是記錄的最新版本,而且讀取以後還須要保證其餘併發事務不能修改當前記錄,對讀取的記錄加鎖。

快照讀:不加鎖的非阻塞讀,select;;

            serializable隔離級別下是串行讀,快照讀退化成當前讀;

            快照讀的實現基於多版本併發控制(MVCC),避免了加鎖操做,提升併發性能, 開銷更低;

            快照讀有可能讀到的數據並非最新版本,多是以前的 歷史版本

read committed級別下,當前讀和快照讀的結果同樣的,數據版本同樣,(讀取的是另外一個事務提交後的結果)

A: start transaction .   B: start transaction
A: select 100 (快照讀);   建立新的快照read view  
  B: update 100 + 100
  B: commit
A: select(快照讀) 200; 建立新的快照read view  
A: select lock in share mode(當前讀) 200  
A: commit  

repeatable read級別下,快照讀(讀取的多是數據未修改前的版本,建立快照讀的時機決定了讀取數據的版本),當前讀(讀取的是數據的最新版本)

A: start transaction .   B: start transaction
A: select 100(快照讀)  ,會建立一個快照read view,將當前系統活躍的事務id記錄起來  
  B: update 100 + 100
  B: commit

A: select (快照讀) 100,讀到的是歷史版本;事務開啓後未作讀取操做,則此時讀取的是最新版本 200

使用的是前一個快照的read view

 
A: select lock in share mode(當前讀) 200,最新版本  
A: commit  

READ COMMITTD在每一次進行普通SELECT操做前都會
生成一個ReadView,而REPEATABLE READ只在第一次進行普通SELECT操做前生成一個ReadView,以後的查
詢操做都重複使用這個ReadView就行了

 

next-key鎖(行鎖 + gap鎖)

gap鎖,間隙鎖,鎖定一個範圍但不包括記錄自己,防止同一事務的兩次當前讀出現幻讀的狀況

gap鎖, read uncommitted, read committed 級別下沒有 ,沒法避免幻讀

gap lock會用在非惟一索引和不走索引的當前讀,以及僅命中檢索條件的部分結果集;主鍵索引和惟一索引的當前讀中;

 

repeatable read級別下當前讀(刪改查)對主鍵索引或者惟一索引會用gap鎖嗎?

1.對於主鍵索引和惟一索引的當前讀,若是where條件所有命中(精確查詢時全部記錄都有),則不會用gap鎖,只會加行鎖,若是範圍條件部分命中或者都不命中,則使用Gap鎖。

2.對於主鍵索引和惟一索引的當前讀,用相等條件檢索數據時,存在使用行鎖,不存在使用gap鎖///

3.對於非惟一索引的當前讀:使用Gap鎖

4.對於不走索引的當前讀:使用Gap鎖(至關於鎖表)

總結:插入操做對查詢結果有影響就gap鎖 + 行鎖,沒有隻加行鎖

select * from table where id in (1,3,5),  id爲1,3,5均在該table中存在,所有命中, 事務B新增一條數據在事務A查詢的範圍以外,事務B提交後,事務A再作當前讀仍是原來的數據,不會出現幻讀。

A: start transaction .   B: start transaction

A: delete from tb where id=9 (主鍵索引或惟一索引);

 
 

B: insert into tb value(10),

id=9數據存在,插入成功;不存在失敗阻塞,id=9數據周圍的間隙被鎖住了

A: rollback  

數據庫中數據:4,5,80, 100

當前讀要查詢數據90;(80,90] 和(90,100] 區間會被gap鎖住 

 

7、關鍵語法

1. 統計相關函數

count, sum, max, min, avg

2. group by

3.HAVING

一般和group by子句一塊兒使用

沒有grup by子句,having和where的做用同樣

where過濾行,having過濾組

出如今同一sql中的順序 where > group by > having

相關文章
相關標籤/搜索