1. 程式人生 > >深入理解Mysql——鎖、事務與併發控制

深入理解Mysql——鎖、事務與併發控制

下面大部分博文轉自https://blog.csdn.net/lemon89/article/details/51477497

SQL 語句主要可以劃分為以下 3 個類別。

DDL(Data Definition Languages)語句:資料定義語言,這些語句定義了不同的資料段、資料庫、表、列、索引等資料庫物件的定義。常用的語句關鍵字主要包括 create、drop、alter等。

DML(Data Manipulation Language)語句:資料操縱語句,用於新增、刪除、更新和查詢資料庫記錄,並檢查資料完整性,常用的語句關鍵字主要包括 insert、delete、udpate 和select 等。(增添改查)

DCL(Data Control Language)語句:資料控制語句,用於控制不同資料段直接的許可和訪問級別的語句。這些語句定義了資料庫、表、欄位、使用者的訪問許可權和安全級別。主要的語句關鍵字包括 grant、revoke 等。

DDL 語句:

DDL 是資料定義語言的縮寫,簡單來說,就是對資料庫內部的物件進行建立、刪除、修改的操作語言。它和 DML 語言的最大區別是 DML 只是對錶內部資料的操作,而不涉及到表的定義、結構的修改,更不會涉及到其他物件。DDL 語句更多的被資料庫管理員(DBA)所使用,一般的開發人員很少使用。

mysql併發控制——共享鎖、排他鎖

共享鎖

共享鎖也稱為讀鎖,讀鎖允許多個連線可以同一時刻併發的讀取同一資源,互不干擾;

排他鎖

排他鎖也稱為寫鎖,一個寫鎖會阻塞其他的寫鎖或讀鎖,保證同一時刻只有一個連線可以寫入資料,同時防止其他使用者對這個資料的讀寫。

鎖策略

鎖的開銷是較為昂貴的,鎖策略其實就是保證了執行緒安全的同時獲取最大的效能之間的平衡策略。

  • mysql鎖策略:talbe lock(表鎖)

表鎖是mysql最基本的鎖策略,也是開銷最小的鎖,它會鎖定整個表;

具體情況是:若一個使用者正在執行寫操作,會獲取排他的“寫鎖”,這可能會鎖定整個表,阻塞其他使用者的讀、寫操作;

若一個使用者正在執行讀操作,會先獲取共享鎖“讀鎖”,這個鎖執行其他讀鎖併發的對這個表進行讀取,互不干擾。只要沒有寫鎖的進入,讀鎖可以是併發讀取統一資源的。

通常發生在DDL語句\DML不走索引的語句中,比如這個DML update table set columnA=”A” where columnB=“B”. 

如果columnB欄位不存在索引(或者不是組合索引字首),會鎖住所有記錄也就是鎖表。如果語句的執行能夠執行一個columnB欄位的索引,那麼會鎖住滿足where的行(行鎖)。

通過SELECT * from information_schema.INNODB_TRX這一句可以看每個事務的鎖的情況

我在事務A中查詢一條資料

select * from tab1 where column1 = xxx for update   column1是沒有索引的

這時trx_rows_locked鎖的是全表的數量,當我給column1加上索引時,就只鎖了一行

  • mysql鎖策略:row lock(行鎖)

行鎖可以最大限度的支援併發處理,當然也帶來了最大開銷,顧名思義,行鎖的粒度實在每一條行資料。

REPEATABLE READ(可重複讀)

一個事務中多次執行統一讀SQL,返回結果一樣。  這個隔離級別解決了髒讀的問題,幻讀問題(現在網路上還有很多文章說,Repetable read級別會有幻讀問題,其實已經沒有了)。這裡指的是innodb的rr級別,innodb中使用next-key鎖對”當前讀”進行加鎖,鎖住行以及可能產生幻讀的插入位置,阻止新的資料插入產生幻行。 

多版本併發控制-MVCC

MVCC(multiple-version-concurrency-control)是個行級鎖的變種,它在普通讀情況下避免了加鎖操作,因此開銷更低。  雖然實現不同,但通常都是實現非阻塞讀,對於寫操作只鎖定必要的行

  • 一致性讀 (就是讀取快照)  select * from table ….;
  • 當前讀(就是讀取實際的持久化的資料)  特殊的讀操作,插入/更新/刪除操作,屬於當前讀,處理的都是當前的資料,需要加鎖。  select * from table where ? lock in share mode;  select * from table where ? for update;  insert;  update ;  delete;

注意:select …… from where…… (沒有額外加鎖字尾)使用MVCC,保證了讀快照(mysql稱為consistent read),所謂一致性讀或者讀快照就是讀取當前事務開始之前的資料快照,在這個事務開始之後的更新不會被讀到。詳細情況下文select的詳述。

對於加鎖讀SELECT with FOR UPDATE(排他鎖) or LOCK IN SHARE MODE(共享鎖)、update、delete語句,要考慮是否是唯一索引的等值查詢。

MVCC 可以保證,假如說你這條資料被很多地方用到,然後我這個地方加了鎖,不會影響其它沒加鎖的地方,比如說我加了for update,如果沒有MVCC,則所有查詢都會被阻塞,有了MVCC,就只有同樣加for update會被阻塞

寫鎖-recordLock,gapLock,next key lock

對於使用到唯一索引 等值查詢:比如,where columnA=”…” ,如果columnA上的索引被使用到, 

那麼會在滿足where的記錄上加行鎖(for update是排他鎖,lock in shared 是共享鎖,其他寫操作加排他鎖)。這裡是行級鎖,record lock。

我拿id作了驗證,只鎖住了相關行

對於範圍查詢(使用非唯一的索引): 

比如(做範圍查詢):where columnA between 10 and 30 ,會導致其他會話中10以後的資料都無法插入(next key lock),從而解決了幻讀問題。

事務1相關行是25行

我們用select * from information_schema.INNODB_TRX查詢一下鎖住的行

發現它鎖了51行,也就是說它不僅鎖了相關的25行,還鎖住了周圍的行.

將事務1的SQL改一下

select * from t_product where sort_id BETWEEN 182 and 183 for update; 

再次執行事務1(未提交)

然後寫一新的事務2

set autocommit = 0; START TRANSACTION;

select * from t_product where sort_id=181 for update; 

可以發現,這個查詢並沒有被阻塞,也就是說181的資料都沒有被鎖,改一下SQL

select * from t_product where sort_id=184 for update; 

就發現184的資料已經被鎖了

上面的實驗就是證明此文對於範圍查詢,鎖會怎麼鎖的說法是對的

這裡是next key lock 會包括涉及到的所有行。 

next key lock=recordLock+gapLock,不僅鎖住相關資料,而且鎖住邊界,從而徹底避免幻讀