日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

【转】【MySQL】事务与锁(四):行锁到底锁住的是什么?记录?字段?索引?

發布時間:2023/12/10 数据库 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转】【MySQL】事务与锁(四):行锁到底锁住的是什么?记录?字段?索引? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

首先我們有三張表t1,t2,t3,它們都是只有兩個字段, int類型的id和varchar類型的name;區別是t1沒有索引,t2有主鍵索引,t3有唯一索引。

再強調一次,在實驗前必須提前關閉自動提交,set autocommit=off。然后show variables like 'autocommit'查看自動提交是否是off。

我們先假設InnoDB的鎖鎖住了是一行數據或者一條記錄。

1.假設鎖住記錄

1.1 實驗一:沒有索引的表(t1)

這個實驗操作是操作沒有索引的t1,t1里面有4條數據:1、2、3、4。

現在我們在兩個會話里面手工開啟兩個事務。在第一個事務里面,我們通過where id =1 鎖住第一行數據。在第二個事務里面,我們嘗試給id=3的這一行數據加鎖,大家覺得能成功嗎?

Transaction1Transaction2
Begin;?
SELECT * FROM t1 where id=1 FOR UPDATE;?
?Begin;
?SELECT * FROM t1 where id=3 FOR UPDATE; // BLOCKED
?INSERT INTO t1 (id, name) VALUES (5, ‘5’); // BLOCKED

這就有點奇怪了,第一個事務鎖住了id=1的這行數據,為什么我不能操作id=3的數據呢?我們再來操作一條不存在的數據,插入id=5。它也被阻塞了。實際上這里整張表都被鎖住了。所以,我們的第一個猜想被推翻了,InnoDB的鎖鎖住的應該不是Record。

那為什么在沒有索引或者沒有用到索引的情況下,會鎖住整張表?這個問題我們先留在這里。下面繼續看第二個實驗。

1.2 實驗二:有主鍵索引的表(t2)

我們先看一下t2的表結構。字段是一樣的,不同的地方是id上創建了一個主鍵索引。里面的數據是 1、4、7、10。

Transaction1Transaction2
Begin;?
SELECT * FROM t2 where id=1 FOR UPDATE;?
?Begin;
?SELECT * FROM t2 where id=1 FOR UPDATE; // BLOCKED
?SELECT * FROM t2 where id=4 FOR UPDATE; // OK

第一種情況,使用相同的id值去加鎖,沖突;使用不同的id加鎖,可以加鎖成功。

那么出現問題了,從實驗一中得到鎖定的不是一行數據,但是實驗二操作不同記錄的數據又可以成功,那有沒有可能是鎖住了id的這個字段呢?

2.假設鎖住字段

我們看一下 t3 的表結構。字段還是一樣的, id上創建了一個主鍵索引,name上創建了一個唯一索引。里面的數據是1、4、7、10。

在第一個事務里面,我們通過name字段去鎖定值是4的這行數據。在第二個事務里面,嘗試獲取一樣的排它鎖,肯定是失敗的,這個不用懷疑。在這里我們懷疑InnoDB鎖住的是字段,所以這次我換一個字段,用id=4去給這行數據加鎖,大家覺得能成功嗎?

Transaction1Transaction2
Begin;?
SELECT * FROM t3 where name=‘4’ FOR UPDATE;?
?Begin;
?SELECT * FROM t3 where name=‘4’ FOR UPDATE; // BLOCKED
?SELECT * FROM t3 where id=4 FOR UPDATE; // BLOCKED

很遺憾,又被阻塞了,說明鎖住的是字段的這個推測也是錯的,否則就不會出現第一個事務鎖住了name,第二個字段鎖住id失敗的情況。

既然鎖住的不是record,也不是column, InnoDB里面鎖住的到底是什么呢?

3.其實,鎖的是索引

在這三個案例里面,我們要去分析一下他們的差異在哪里,也就是這三張表的結構,是什么區別導致了加鎖的行為的差異?其實答案就是索引。?InnoDB的行鎖,就是通過鎖住索引來實現的

那索引又是個什么東西?為什么它可以被鎖住?我們在?【MySQL】詳談索引存儲結構推演過程?已經分析過了。那么我們還有兩個問題沒有解決:

問題一:為什么表里面沒有索引的時候,實驗一鎖住一行數據會導致鎖表?或者說,如果鎖住的是索引,一張表沒有索引怎么辦?所以,一張表有沒有可能沒有索引?

  • 如果我們定義了主鍵(PRIMARYKEY),那么 InnoDB 會選擇主鍵作為聚集索引
  • 如果沒有顯式定義主鍵,則 InnoDB 會選擇第一個不包含有 NULL 值的唯一索引作為主鍵索引
  • 如果也沒有這樣的唯一索引,則 InnoDB 會選擇內置 6 字節長的 ROWID 作為隱藏的聚集索引,它會隨著行記錄的寫入而主鍵遞增
  • 所以,實驗一為什么鎖表,是因為查詢沒有使用索引,會進行全表掃描,然后把每一個隱藏的聚集索引都鎖住了。

    問題二:實驗二為什么通過唯一索引給數據行加鎖,主鍵索引也會被鎖住?

    在輔助索引里面, 索引存儲的是二級索引和主鍵的值。 比如name=4,存儲的是name的索引和主鍵id的值4。而主鍵索引里面除了索引之外,還存儲了完整的數據。所以我們通過輔助索引鎖定一行數據的時候,它跟我們檢索數據的步驟是一樣的,會通過主鍵值找到主鍵索引,然后也鎖定。

    ?

    復雜官網的一句話,A record lock is a lock on an index record,是不是只有【記錄鎖】是鎖索引,其他鎖是鎖住行或表?

    回復:行鎖、表鎖是對于鎖粒度而言的,是一對最廣泛的概念。表鎖的實現很好想,就是需要一個標志來記錄當前有沒有事務已經來操做表了。而行鎖的實現是鎖的索引,根據鎖索引的范圍又可以分為記錄鎖、間隙鎖、臨鍵鎖。 比如說我們修改一個數據庫已經有的記錄,那直接鎖相應索引就行(記錄鎖);再比如我們給一張有兩條數據的表(id=1,id=10)進行范圍查詢并加鎖 where id>2 and id < 5 for update,此時命中了一個不存在數據的區間(2,5),這時該鎖哪?是鎖兩個索引之間的整個區間(1,10),這就是間隙鎖。臨鍵鎖=記錄鎖+間隙鎖,這里就不說了,可以看我的這篇文章 https://blog.csdn.net/weixin_43935927/article/details/109410420

    總結

    以上是生活随笔為你收集整理的【转】【MySQL】事务与锁(四):行锁到底锁住的是什么?记录?字段?索引?的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。