c++客戶端發送加鎖_MySQL語句加鎖分析詳解

前言

建立一個存儲三國英雄的hero表:

CREATE TABLE hero (
number INT,
name VARCHAR(100),
country varchar(100),
PRIMARY KEY (number),
KEY idx_name (name)
) Engine=InnoDB CHARSET=utf8;

然后向這個表里插入幾條記錄:

INSERT INTO hero VALUES
(1, 'l劉備', '蜀'),
(3, 'z諸葛亮', '蜀'),
(8, 'c曹操', '魏'),
(15, 'x荀彧', '魏'),
(20, 's孫權', '吳');

然后現在hero表就有了兩個索引(一個二級索引,一個聚簇索引),示意圖如下:

27657467af7c83cd5384a04b037b796d.png

語句加鎖分析

其實啊,“XXX語句該加什么鎖”本身就是個偽命題,一條語句需要加的鎖受到很多條件制約,比方說:

  • 事務的隔離級別

  • 語句執行時使用的索引(比如聚簇索引、唯一二級索引、普通二級索引)

  • 查詢條件(比方說==<>=等等)

  • 具體執行的語句類型

在繼續詳細分析語句的加鎖過程前,大家一定要有一個全局概念:加鎖只是解決并發事務執行過程中引起的臟寫臟讀不可重復讀幻讀這些問題的一種解決方案(MVCC算是一種解決臟讀不可重復讀幻讀這些問題的一種解決方案),一定要意識到加鎖的出發點是為了解決這些問題,不同情景下要解決的問題不一樣,才導致加的鎖不一樣,千萬不要為了加鎖而加鎖,容易把自己繞進去。當然,有時候因為MySQL具體的實現而導致一些情景下的加鎖有些不太好理解,這就得我們死記硬背了~

我們這里把語句分為3種大類:普通的SELECT語句、鎖定讀的語句、INSERT語句,我們分別看一下。

普通的SELECT語句

普通的SELECT語句在:

  • READ UNCOMMITTED隔離級別下,不加鎖,直接讀取記錄的最新版本,可能發生臟讀不可重復讀幻讀問題。

  • READ COMMITTED隔離級別下,不加鎖,在每次執行普通的SELECT語句時都會生成一個ReadView,這樣解決了臟讀問題,但沒有解決不可重復讀幻讀問題。

  • REPEATABLE READ隔離級別下,不加鎖,只在第一次執行普通的SELECT語句時生成一個ReadView,這樣把臟讀不可重復讀幻讀問題都解決了。

    不過這里有一個小插曲:

    # 事務T1,REPEATABLE READ隔離級別下
    mysql> BEGIN;
    Query OK, 0 rows affected (0.00 sec)
    mysql> SELECT * FROM hero WHERE number = 30;
    Empty set (0.01 sec)# 此時事務T2執行了:INSERT INTO hero VALUES(30, 'g關羽', '魏'); 并提交
    mysql> UPDATE hero SET country = '蜀' WHERE number = 30;
    Query OK, 1 row affected (0.01 sec)
    Rows matched: 1 Changed: 1 Warnings: 0
    mysql> SELECT * FROM hero WHERE number = 30;
    +--------+---------+---------+
    | number | name | country |
    +--------+---------+---------+
    | 30 | g關羽 | 蜀 |
    +--------+---------+---------+
    1 row in set (0.01 sec)

    REPEATABLE READ隔離級別下,T1第一次執行普通的SELECT語句時生成了一個ReadView,之后T2hero表中新插入了一條記錄便提交了,ReadView并不能阻止T1執行UPDATE或者DELETE語句來對改動這個新插入的記錄(因為T2已經提交,改動該記錄并不會造成阻塞),但是這樣一來這條新記錄的trx_id隱藏列就變成了T1事務id,之后T1中再使用普通的SELECT語句去查詢這條記錄時就可以看到這條記錄了,也就把這條記錄返回給客戶端了。因為這個特殊現象的存在,你也可以認為InnoDB中的MVCC并不能完完全全的禁止幻讀。

  • SERIALIZABLE隔離級別下,需要分為兩種情況討論:

    • 在系統變量autocommit=0時,也就是禁用自動提交時,普通的SELECT語句會被轉為SELECT ... LOCK IN SHARE MODE這樣的語句,也就是在讀取記錄前需要先獲得記錄的S鎖,具體的加鎖情況和REPEATABLE READ隔離級別下一樣,我們后邊再分析。

    • 在系統變量autocommit=1時,也就是啟用自動提交時,普通的SELECT語句并不加鎖,只是利用MVCC來生成一個ReadView去讀取記錄。

      為啥不加鎖呢?因為啟用自動提交意味著一個事務中只包含一條語句,一條語句也就沒有啥不可重復讀幻讀這樣的問題了。

鎖定讀的語句

我們把下邊四種語句放到一起討論:

  • 語句一:SELECT ... LOCK IN SHARE MODE;

  • 語句二:SELECT ... FOR UPDATE;

  • 語句三:UPDATE ...

  • 語句四:DELETE ...

我們說語句一語句二MySQL中規定的兩種鎖定讀的語法格式,而語句三語句四由于在執行過程需要首先定位到被改動的記錄并給記錄加鎖,也可以被認為是一種鎖定讀

READ UNCOMMITTED/READ COMMITTED隔離級別下

READ UNCOMMITTED下語句的加鎖方式和READ COMMITTED隔離級別下語句的加鎖方式基本一致,所以就放到一塊兒說了。值得注意的是,采用加鎖方式解決并發事務帶來的問題時,其實臟讀不可重復讀在任何一個隔離級別下都不會發生(因為讀-寫操作需要排隊進行)。

對于使用主鍵進行等值查詢的情況
  • 使用SELECT ... LOCK IN SHARE MODE來為記錄加鎖,比方說:

    SELECT * FROM hero WHERE number = 8 LOCK IN SHARE MODE;

    這個語句執行時只需要訪問一下聚簇索引中number值為8的記錄,所以只需要給它加一個S型正經記錄鎖就好了,如圖所示:

    fe51383a44638db3c3046b2f0cad7f15.png
  • 使用SELECT ... FOR UPDATE來為記錄加鎖,比方說:

    SELECT * FROM hero WHERE number = 8 FOR UPDATE;

    這個語句執行時只需要訪問一下聚簇索引中number值為8的記錄,所以只需要給它加一個X型正經記錄鎖就好了,如圖所示:

    4683a0063cd2fdc8ea6f0398a9b8cbd3.png

    小貼士:為了區分S鎖和X鎖,我們之后在示意圖中就把加了S鎖的記錄染成藍色,把加了X鎖的記錄染成紫色。

  • 使用UPDATE ...來為記錄加鎖,比方說:

    UPDATE hero SET country = '漢' WHERE number = 8;

    這條UPDATE語句并沒有更新二級索引列,加鎖方式和上邊所說的SELECT ... FOR UPDATE語句一致。

    如果UPDATE語句中更新了二級索引列,比方說:

    UPDATE hero SET name = 'cao曹操' WHERE number = 8;

    該語句的實際執行步驟是首先更新對應的number值為8的聚簇索引記錄,再更新對應的二級索引記錄,所以加鎖的步驟就是:

  1. number值為8的聚簇索引記錄加上X型正經記錄鎖(該記錄對應的)。

  2. 為該聚簇索引記錄對應的idx_name二級索引記錄(也就是name值為'c曹操'number值為8的那條二級索引記錄)加上X型正經記錄鎖

畫個圖就是這樣:

719b7521abb2f111f92098446f604caf.png

小貼士:我們用帶圓圈的數字來表示為各條記錄加鎖的順序。

使用DELETE ...來為記錄加鎖,比方說:

DELETE FROM hero WHERE number = 8;

我們平時所說的“DELETE表中的一條記錄”其實意味著對聚簇索引和所有的二級索引中對應的記錄做DELETE操作,本例子中就是要先把number值為8的聚簇索引記錄執行DELETE操作,然后把對應的idx_name二級索引記錄刪除,所以加鎖的步驟和上邊更新帶有二級索引列的UPDATE語句一致,就不畫圖了。

對于使用主鍵進行范圍查詢的情況
  • 使用SELECT ... LOCK IN SHARE MODE來為記錄加鎖,比方說:

    SELECT * FROM hero WHERE number <= 8 LOCK IN SHARE MODE;

    這個語句看起來十分簡單,但它的執行過程還是有一丟丟小復雜的:

  1. 先到聚簇索引中定位到滿足number <= 8的第一條記錄,也就是number值為1的記錄,然后為其加鎖。

  2. 判斷一下該記錄是否符合索引條件下推中的條件。

    我們前邊介紹過一個稱之為索引條件下推(?Index Condition Pushdown,簡稱ICP)的功能,也就是把查詢中與被使用索引有關的查詢條件下推到存儲引擎中判斷,而不是返回到server層再判斷。不過需要注意的是,索引條件下推只是為了減少回表次數,也就是減少讀取完整的聚簇索引記錄的次數,從而減少IO操作。而對于聚簇索引而言不需要回表,它本身就包含著全部的列,也起不到減少IO操作的作用,所以設計InnoDB的大叔們規定這個索引條件下推特性只適用于二級索引。也就是說在本例中與被使用索引有關的條件是:number <= 8,而number列又是聚簇索引列,所以本例中并沒有符合索引條件下推的查詢條件,自然也就不需要判斷該記錄是否符合索引條件下推中的條件。

  3. 判斷一下該記錄是否符合范圍查詢的邊界條件

    因為在本例中是利用主鍵number進行范圍查詢,設計InnoDB的大叔規定每從聚簇索引中取出一條記錄時都要判斷一下該記錄是否符合范圍查詢的邊界條件,也就是number <= 8這個條件。如果符合的話將其返回給server層繼續處理,否則的話需要釋放掉在該記錄上加的鎖,并給server層返回一個查詢完畢的信息。

    對于number值為1的記錄是符合這個條件的,所以會將其返回到server層繼續處理。

  4. 將該記錄返回到server層繼續判斷。

    server層如果收到存儲引擎層提供的查詢完畢的信息,就結束查詢,否則繼續判斷那些沒有進行索引條件下推的條件,在本例中就是繼續判斷number <= 8這個條件是否成立。噫,不是在第3步中已經判斷過了么,怎么在這又判斷一回?是的,設計InnoDB的大叔采用的策略就是這么簡單粗暴,把凡是沒有經過索引條件下推的條件都需要放到server層再判斷一遍。如果該記錄符合剩余的條件(沒有進行索引條件下推的條件),那么就把它發送給客戶端,不然的話需要釋放掉在該記錄上加的鎖。

  5. 然后剛剛查詢得到的這條記錄(也就是number值為1的記錄)組成的單向鏈表繼續向后查找,得到了number值為3的記錄,然后重復第2345這幾個步驟。

小貼士:上述步驟是在MySQL 5.7.21這個版本中驗證的,不保證其他版本有無出入。

但是這個過程有個問題,就是當找到number值為8的那條記錄的時候,還得向后找一條記錄(也就是number值為15的記錄),在存儲引擎讀取這條記錄的時候,也就是上述的第1步中,就得為這條記錄加鎖,然后在第3步時,判斷該記錄不符合number <= 8這個條件,又要釋放掉這條記錄的鎖,這個過程導致number值為15的記錄先被加鎖,然后把鎖釋放掉,過程就是這樣:

f6c2586673f69e1e3e6c6191b54daec3.png

這個過程有意思的一點就是,如果你先在事務T1中執行:

# 事務T1
BEGIN;
SELECT * FROM hero WHERE number <= 8 LOCK IN SHARE MODE;

然后再到事務T2中執行:

# 事務T2
BEGIN;
SELECT * FROM hero WHERE number = 15 FOR UPDATE;

是沒有問題的,因為在T2執行時,事務T1已經釋放掉了number值為15的記錄的鎖,但是如果你先執行T2,再執行T1,由于T2已經持有了number值為15的記錄的鎖,事務T1將因為獲取不到這個鎖而等待。

我們再看一個使用主鍵進行范圍查詢的例子:

SELECT * FROM hero WHERE number >= 8 LOCK IN SHARE MODE;

這個語句的執行過程其實和我們舉的上一個例子類似。也是先到聚簇索引中定位到滿足number >= 8這個條件的第一條記錄,也就是number值為8的記錄,然后就可以沿著由記錄組成的單向鏈表一路向后找,每找到一條記錄,就會為其加上鎖,然后判斷該記錄符不符合范圍查詢的邊界條件,不過這里的邊界條件比較特殊:number >= 8,只要記錄不小于8就算符合邊界條件,所以判斷和沒判斷是一樣一樣的。最后把這條記錄返回給server層server層再判斷number >= 8這個條件是否成立,如果成立的話就發送給客戶端,否則的話就結束查詢。不過InnoDB存儲引擎找到索引中的最后一條記錄,也就是Supremum偽記錄之后,在存儲引擎內部就可以立即判斷這是一條偽記錄,不必要返回給server層處理,也沒必要給它也加上鎖(也就是說在第1步中就壓根兒沒給這條記錄加鎖)。整個過程會給number值為81520這三條記錄加上S型正經記錄鎖,畫個圖表示一下就是這樣:

22765cccf2ca3db875df1f1961a4bc11.png

使用SELECT ... FOR UPDATE語句來為記錄加鎖:

SELECT ... FOR UPDATE語句類似,只不過加的是X型正經記錄鎖

使用UPDATE ...來為記錄加鎖,比方說:

UPDATE hero SET country = '漢' WHERE number >= 8;

這條UPDATE語句并沒有更新二級索引列,加鎖方式和上邊所說的SELECT ... FOR UPDATE語句一致。

如果UPDATE語句中更新了二級索引列,比方說:

UPDATE hero SET name = 'cao曹操' WHERE number >= 8;

這時候會首先更新聚簇索引記錄,再更新對應的二級索引記錄,所以加鎖的步驟就是:

  1. number值為8的聚簇索引記錄加上X型正經記錄鎖

  2. 然后為上一步中的記錄索引記錄對應的idx_name二級索引記錄加上X型正經記錄鎖

  3. number值為15的聚簇索引記錄加上X型正經記錄鎖

  4. 然后為上一步中的記錄索引記錄對應的idx_name二級索引記錄加上X型正經記錄鎖

  5. number值為20的聚簇索引記錄加上X型正經記錄鎖

  6. 然后為上一步中的記錄索引記錄對應的idx_name二級索引記錄加上X型正經記錄鎖

畫個圖就是這樣:

8f1310f1dc53edb5a82e573f88f7141c.png

如果是下邊這個語句:

UPDATE hero SET namey = '漢' WHERE number <= 8;

則會對number值為138聚簇索引記錄以及它們對應的二級索引記錄加X型正經記錄鎖,加鎖順序和上邊語句中的加鎖順序類似,都是先對一條聚簇索引記錄加鎖后,再給對應的二級索引記錄加鎖。之后會繼續對number值為15的聚簇索引記錄加鎖,但是隨后InnoDB存儲引擎判斷它不符合邊界條件,隨即會釋放掉該聚簇索引記錄上的鎖(注意這個過程中沒有對number值為15的聚簇索引記錄對應的二級索引記錄加鎖)。具體示意圖就不畫了。

使用DELETE ...來為記錄加鎖,比方說:

DELETE FROM hero WHERE number >= 8;

DELETE FROM hero WHERE number <= 8;

這兩個語句的加鎖情況和更新帶有二級索引列的UPDATE語句一致,就不畫圖了。

對于使用二級索引進行等值查詢的情況

小貼士:在READ UNCOMMITTED和READ COMMITTED隔離級別下,使用普通的二級索引和唯一二級索引進行加鎖的過程是一樣的,所以我們也就不分開討論了。

  • 使用SELECT ... LOCK IN SHARE MODE來為記錄加鎖,比方說:

    SELECT * FROM hero WHERE name = 'c曹操' LOCK IN SHARE MODE;

    這個語句的執行過程是先通過二級索引idx_name定位到滿足name = 'c曹操'條件的二級索引記錄,然后進行回表操作。所以先要對二級索引記錄加S型正經記錄鎖,然后再給對應的聚簇索引記錄加S型正經記錄鎖,示意圖如下:

    53f780ec630f6e5469be61b734bd785d.png

    這里需要再次強調一下這個語句的加鎖順序:

  1. 先對name列為'c曹操'二級索引記錄進行加鎖。

  2. 再對相應的聚簇索引記錄進行加鎖

小貼士:我們知道idx_name是一個普通的二級索引,到idx_name索引中定位到滿足name= 'c曹操'這個條件的第一條記錄后,就可以沿著這條記錄一路向后找。可是從我們上邊的描述中可以看出來,并沒有對下一條二級索引記錄進行加鎖,這是為什么呢?這是因為設計InnoDB的大叔對等值匹配的條件有特殊處理,他們規定在InnoDB存儲引擎層查找到當前記錄的下一條記錄時,在對其加鎖前就直接判斷該記錄是否滿足等值匹配的條件,如果不滿足直接返回(也就是不加鎖了),否則的話需要將其加鎖后再返回給server層。所以這里也就不需要對下一條二級索引記錄進行加鎖了。

現在要介紹一個非常有趣的事情,我們假設上邊這個語句在事務T1中運行,然后事務T2中運行下邊一個我們之前介紹過的語句:

UPDATE hero SET name = '曹操' WHERE number = 8;

這兩個語句都是要對number值為8的聚簇索引記錄和對應的二級索引記錄加鎖,但是不同點是加鎖的順序不一樣。這個UPDATE語句是先對聚簇索引記錄進行加鎖,后對二級索引記錄進行加鎖,如果在不同事務中運行上述兩個語句,可能發生一種賊奇妙的事情 ——

  • 事務T2持有了聚簇索引記錄的鎖,事務T1持有了二級索引記錄的鎖。

  • 事務T2在等待獲取二級索引記錄上的鎖,事務T1在等待獲取聚簇索引記錄上的鎖。

兩個事務都分別持有一個鎖,而且都在等待對方已經持有的那個鎖,這種情況就是所謂的死鎖,兩個事務都無法運行下去,必須選擇一個進行回滾,對性能影響比較大。??

使用SELECT ... FOR UPDATE語句時,比如:

SELECT * FROM hero WHERE name = 'c曹操' FOR UPDATE;

這種情況下與SELECT ... LOCK IN SHARE MODE語句的加鎖情況類似,都是給訪問到的二級索引記錄和對應的聚簇索引記錄加鎖,只不過加的是X型正經記錄鎖罷了。

使用UPDATE ...來為記錄加鎖,比方說:

與更新二級索引記錄的SELECT ... FOR UPDATE的加鎖情況類似,不過如果被更新的列中還有別的二級索引列的話,對應的二級索引記錄也會被加鎖。

使用DELETE ...來為記錄加鎖,比方說:

SELECT ... FOR UPDATE的加鎖情況類似,不過如果表中還有別的二級索引列的話,對應的二級索引記錄也會被加鎖。

對于使用二級索引進行范圍查詢的情況
  • 使用SELECT ... LOCK IN SHARE MODE來為記錄加鎖,比方說:

    SELECT * FROM hero FORCE INDEX(idx_name)  WHERE name >= 'c曹操' LOCK IN SHARE MODE;

    小貼士:因為優化器會計算使用二級索引進行查詢的成本,在成本較大時可能選擇以全表掃描的方式來執行查詢,所以我們這里使用FORCE INDEX(idx_name)來強制使用二級索引idx_name來執行查詢。

    這個語句的執行過程其實是先到二級索引中定位到滿足name >= 'c曹操'的第一條記錄,也就是name值為c曹操的記錄,然后就可以沿著這條記錄的鏈表一路向后找,從二級索引idx_name的示意圖中可以看出,所有的用戶記錄都滿足name >= 'c曹操'的這個條件,所以所有的二級索引記錄都會被加S型正經記錄鎖,它們對應的聚簇索引記錄也會被加S型正經記錄鎖。不過需要注意一下加鎖順序,對一條二級索引記錄加鎖完后,會接著對它相應的聚簇索引記錄加鎖,完后才會對下一條二級索引記錄進行加鎖,以此類推~ 畫個圖表示一下就是這樣:

    5aa788827a49ad4d24731242c580b9e3.png

    再來看下邊這個語句:

    SELECT * FROM hero FORCE INDEX(idx_name) WHERE name <= 'c曹操' LOCK IN SHARE MODE;

    這個語句的加鎖情況就有點兒有趣了。前邊說在使用number <= 8這個條件的語句中,需要把number值為15的記錄也加一個鎖,之后又判斷它不符合邊界條件而把鎖釋放掉。而對于查詢條件name <= 'c曹操'的語句來說,執行該語句需要使用到二級索引,而與二級索引相關的條件是可以使用索引條件下推這個特性的。設計InnoDB的大叔規定,如果一條記錄不符合索引條件下推中的條件的話,直接跳到下一條記錄(這個過程根本不將其返回到server層),如果這已經是最后一條記錄,那么直接向server層報告查詢完畢。但是這里頭有個問題呀:先對一條記錄加了鎖,然后再判斷該記錄是不是符合索引條件下推的條件,如果不符合直接跳到下一條記錄或者直接向server層報告查詢完畢,這個過程中并沒有把那條被加鎖的記錄上的鎖釋放掉呀!!!。本例中使用的查詢條件是name <= 'c曹操',在為name值為'c曹操'的二級索引記錄以及它對應的聚簇索引加鎖之后,會接著二級索引中的下一條記錄,也就是name值為'l劉備'的那條二級索引記錄,由于該記錄不符合索引條件下推的條件,而且是范圍查詢的最后一條記錄,會直接向server層報告查詢完畢,重點是這個過程中并不會釋放name值為'l劉備'的二級索引記錄上的鎖,也就導致了語句執行完畢時的加鎖情況如下所示:

    31ed4791ce193a592c7a3665e572b78c.png

    這樣子會造成一個尷尬情況,假如T1執行了上述語句并且尚未提交,T2再執行這個語句:

    SELECT * FROM hero WHERE name = 'l劉備' FOR UPDATE;

    T2中的語句需要獲取name值為l劉備的二級索引記錄上的X型正經記錄鎖,而T1中仍然持有name值為l劉備的二級索引記錄上的S型正經記錄鎖,這就造成了T2獲取不到鎖而進入等待狀態。

    小貼士:為啥不能釋放不符合索引條件下推中的條件的二級索引記錄上的鎖呢?這個問題我也沒想明白,人家就是這么規定的,如果有明白的小伙伴可以加我微信 xiaohaizi4919 來討論一下哈~ 再強調一下,我使用的MySQL版本是5.7.21,不保證其他版本中的加鎖情景是否完全一致。

  • 使用SELECT ... FOR UPDATE語句時:

    SELECT ... FOR UPDATE語句類似,只不過加的是X型正經記錄鎖

  • 使用UPDATE ...來為記錄加鎖,比方說:

    UPDATE hero SET country = '漢' WHERE name >= 'c曹操';

    小貼士:FORCE INDEX只對SELECT語句起作用,UPDATE語句雖然支持該語法,但實質上不起作用,DELETE語句壓根兒不支持該語法。

    假設該語句執行時使用了idx_name二級索引來進行鎖定讀,那么它的加鎖方式和上邊所說的SELECT ... FOR UPDATE語句一致。如果有其他二級索引列也被更新,那么也會為對應的二級索引記錄進行加鎖,就不贅述了。不過還有一個有趣的情況,比方說:

    UPDATE hero SET country = '漢' WHERE name <= 'c曹操';

    我們前邊說的索引條件下推這個特性只適用于SELECT語句,也就是說UPDATE語句中無法使用,那么這個語句就會為name值為'c曹操''l劉備'的二級索引記錄以及它們對應的聚簇索引進行加鎖,之后在判斷邊界條件時發現name值為'l劉備'的二級索引記錄不符合name <= 'c曹操'條件,再把該二級索引記錄和對應的聚簇索引記錄上的鎖釋放掉。這個過程如下圖所示:

    001c29c6957a18c1655191e47cc25c6b.png
  • 使用DELETE ...來為記錄加鎖,比方說:

    DELETE FROM hero WHERE name >= 'c曹操';

    DELETE FROM hero WHERE name <= 'c曹操';

    如果這兩個語句采用二級索引來進行鎖定讀,那么它們的加鎖情況和更新帶有二級索引列的UPDATE語句一致,就不畫圖了。

全表掃描的情況

比方說:

SELECT * FROM hero WHERE country  = '魏' LOCK IN SHARE MODE;

由于country列上未建索引,所以只能采用全表掃描的方式來執行這條查詢語句,存儲引擎每讀取一條聚簇索引記錄,就會為這條記錄加鎖一個S型正常記錄鎖,然后返回給server層,如果server層判斷country = '魏'這個條件是否成立,如果成立則將其發送給客戶端,否則會釋放掉該記錄上的鎖,畫個圖就像這樣:

3023aa8d1bf2bacbaf9029bbef6a0d49.png

使用SELECT ... FOR UPDATE進行加鎖的情況與上邊類似,只不過加的是X型正經記錄鎖,就不贅述了。

對于UPDATE ...DELETE ...的語句來說,在遍歷聚簇索引中的記錄,都會為該聚簇索引記錄加上X型正經記錄鎖,然后:

  • 如果該聚簇索引記錄不滿足條件,直接把該記錄上的鎖釋放掉。

  • 如果該聚簇索引記錄滿足條件,則會對相應的二級索引記錄加上X型正經記錄鎖(DELETE語句會對所有二級索引列加鎖,UPDATE語句只會為更新的二級索引列對應的二級索引記錄加鎖)。

推薦閱讀

1、徹底搞懂StringBuffer和StringBuilder的區別

2、徒手擼一個Spring MVC框架

3、徒手擼一個MyBatis框架

4、B站視頻上新,?我又擼了一套干貨滿滿的教程滿

4f29ee991aa9cccda7940a223cf6252b.png

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/385929.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/385929.shtml
英文地址,請注明出處:http://en.pswp.cn/news/385929.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

大廠面試必問!如何寫出高效率的SQL

前言 Spring框架自2002年誕生以來一直備受開發者青睞&#xff0c;它包括SpringMVC、SpringBoot、Spring Cloud、Spring Cloud Dataflow等解決方案。有人親切的稱之為&#xff1a;Spring 全家桶。 很多研發人員把spring看作心目中最好的java項目&#xff0c;沒有之一。所以這是…

accsess轉成mysql語句_輕松教你SQL轉ACCESS

SQL數據庫轉access數據庫步驟&#xff1a; 1. 建立access數據庫&#xff1a;在access中建立access數據庫和表&#xff0c;access字段類型與sql中字段類型的對應關系。 2. 在Access中建表是應注意它的保留關鍵字&#xff1a;比如Password 如果表中的某個字段使用了關鍵字&#x…

大廠首發:2021年Java工作或更難找

前言 提起MySQL&#xff0c;其實網上已經有一大把教程了&#xff0c;為什么我還要寫這篇文章呢&#xff0c;大概是因為網上很多網站都是比較零散&#xff0c;而且描述不夠直觀&#xff0c;不能系統對MySQL相關知識有一個系統的學習&#xff0c;導致不能形成知識體系。為此我撰…

linux mysql 運行狀態_Linux中使用mysqladmin extended-status配合Linux命令查看MySQL運行狀態...

mysqladmin是MySQL一個重要的客戶端&#xff0c;最常見的是使用它來關閉數據庫&#xff0c;除此&#xff0c;該命令還可以了解MySQL運行狀態、進程信息、進程殺死等。本文介紹一下如何使用mysqladmin extended-status(因為沒有"歧義"&#xff0c;所以可以使用ext代替…

大廠首發:338頁網易Java面試真題解析火爆全網

前言 為什么互聯網資訊這么發達&#xff0c;但是沒有出現技術人才井噴&#xff1f; 為什么會出現應屆生薪資倒掛多年老員工的現象&#xff1f; 這個世界有太多的現象都可以用**“二八定律”**來解釋。 20%拿著高工資&#xff0c;80%每天掙扎在增刪改查邊緣。 職場一分錢一…

mysql 導入dbm文件_DBM數據導入到mysql數據庫方法

本文章分享一篇關于DBM數據導入到mysql數據庫方法&#xff0c;有需要的同學可以參考一下本實例。首先說明一下&#xff0c;我以前使用PERL&#xff0c;保存文件 用DBM&#xff0c;有5萬多條記錄&#xff0c;每條記錄有15個字段。現在想用MYSQL&#xff0c;要吧記錄導過來。第一…

大牛手把手教你!2021Java最新大廠面試真題

引言 眾所周知&#xff0c;軟件系統有三高&#xff1a;**高并發、高性能、高可用。**三者既有區別也有聯系&#xff0c;門門道道很多&#xff0c;全面討論可以大戰三天三夜。 高并發對于Java開發者來說都不陌生&#xff0c;每年天貓雙十一&#xff0c;秒殺大促等場景阿里都穩…

高通8155車載芯片_WEY來“摩卡”云首秀,搭載高通8155芯片

本期亮點“咖啡”一詞源自埃塞俄比亞的一個名叫卡法的古鎮&#xff0c;在希臘語中“Kaweh”的意思是“力量與熱情“&#xff0c;而摩卡咖啡代表著創新和更多可能性。摩卡咖啡是由濃縮咖啡、牛奶、鮮奶油及巧克力糖漿制成的“巧克力咖啡”&#xff0c;相比于其他制作方法&#x…

大牛深入講解!高并發你真的理解透徹了嗎

前言 最其實不管什么時候&#xff0c;找工作都跑不了面試。目前很多小編都做了面試手冊了&#xff0c;那就是別人家的孩子都有糖了&#xff0c;作為一個自覺的小編&#xff0c;必須搞。 容我先絮叨一下&#xff0c;制作這個面試手冊差不多花了3個多星期時間&#xff0c;過程還…

太厲害了!2021年互聯網大廠Java筆經

開頭 設計模式是一套被反復使用的、多數人知曉的、經過分類編目的、代碼設計經驗的總結。使用設計模式是為了重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。在項目中合理地運用設計模式可以完美地解決很多問題&#xff0c;每種模式在現實中都有相應的原理來與之對應&…

fritzing導入元件_超屌的 fritzing 新建元件

標簽&#xff1a;fritzing 有多好&#xff0c;用了才知道&#xff0c;但是通常會遇到一個問題&#xff0c;他的元件庫不一定夠用&#xff0c;這時候就得自己做元件了&#xff0c;但是搜了一下網上沒有相關的教程啊。算了&#xff0c;去官網看英文吧。。然后官網的幫助見 http:/…

java將字節數組轉換成字符串,面試心得體會

1. 前言 大家都知道&#xff0c;Postman是一個非常受歡迎的API接口調試工具&#xff0c;提供有Chrome擴展插件版和獨立的APP&#xff0c;不過它的很多高級功能都需要付費才能使用。 如果你連Postman都還沒有用過&#xff0c;不妨可以先體驗一番。 Postman官網&#xff1a; h…

linux mysql 刪除表腳本_linux shell腳本自動刪除mysql表前3個月的數據

RDS有一個數據庫表tbl_online表&#xff0c;有6千萬數據&#xff0c;需要清理&#xff0c;保留3個月。步驟如下:創建月表將需要刪除的數據寫入月表刪除數據優化表shell如下:#!/bin/bashbase"rdsxx.mysql.rds.aliyuncs.com"#前3個月的日期months_agodate -d "-3 …

java將數組中的數據修改,深度集成!

京東Java研發崗一面&#xff08;基礎面&#xff0c;約1小時&#xff09; 自我介紹&#xff0c;主要講講做了什么和擅長什么 springmvc和spring-boot區別 Autowired的實現原理 Bean的默認作用范圍是什么&#xff1f;其他的作用范圍&#xff1f; 索引是什么概念有什么作用&am…

mysql oracle 表空間大小_最簡單的查詢表空間的使用量、剩余量的方法 - Focus on Oracle、MySQL and GNU/Linux...

比起用其它的視圖寫長長的一段腳本、簡便多了、據說從7.x到11g都可以用sm$ts_used & sm$ts_freeidle> select * from sm$ts_used;TABLESPACE_NAME BYTES------------------------------ ----------SYSAUX 256573440UNDOTBS1 8323072USERS 3211264SYSTEM 50678988…

java小游戲畢業論文,你不懂還不學?

1. Spring 特點 Spring 主要有如下特點&#xff1a; 輕量級&#xff1a;Spring 是非侵入式&#xff0c;其中的對象不依賴 Spring 的特定類&#xff1b;控制反轉&#xff08;IoC&#xff09;&#xff1a;通過 IoC&#xff0c;促進了低耦合&#xff0c;一個對象依賴的其他對象通…

mysql shell 回車換行_【shell mysql 導出數據到csv腳本,完美解決亂碼轉義符等問題】-費元星...

#!/bin/bash#author&#xff1a;feiyuanxing 【既然笨到家&#xff0c;就要努力到家】#date&#xff1a;2017-12-05#E-Mail&#xff1a;feiyuanxinggmail.com#TARGET:一鍵導出mysql數據到 csv#CopyRight:本腳本遵守 未來星開源協議(http://feiyuanxing.com/kaiyuanxieyi/kaiyua…

java小游戲源代碼資源,一招徹底弄懂!

BATJ大廠面經 阿里七面面經 螞蟻金服面經及答案 京東面經 百度美團順豐京東阿里面經 面試題精選 Java面試手冊 MySQL55題及答案 多線程面試題及答案 設計模式面試題及答案 消息中間件面試題及答案 并發編程面試題及答案 面試資料整理匯總 最后 總而言之&#xff0c;面試官問…

python學法用法 自動刷分器_Python selenium模擬手動操作實現無人值守刷積分功能...

def DaTi(): driver.get(url https://pc.xuexi.cn/points/exam-practice.html) elem_juje WebDriverWait(driver,100).until(EC.presence_of_element_located((By.XPATH,//div[class"q-header"]))) juje elem_juje.get_attribute(innerText) # 在每日答題中&#…

java小程序小游戲代碼貪吃蛇,附高頻面試題合集

One&#xff1a;JVM實踐思維圖&#xff08;完整版&#xff09; Two&#xff1a; 走近Java 概述 Java技術體系Java發展史Java虛擬機家族&#xff1a;&#xff08;Sun Classic/Exact VM、HotSpot VM、Mobile/Embedded VM、BEA JRockit/IBM J9 VM、BEA Liquid VM/Azul VM、Apache…