老劉是即將找工作的研究生,自學大資料開發,一路走來,感慨頗深,網上大資料的資料良莠不齊,於是想寫一份詳細的大資料開發指南。這份指南把大資料的【基礎知識】【框架分析】【原始碼理解】都用自己的話描述出來,讓夥伴自學從此不求人。 您的點贊是我持續更新的動力,禁止白嫖,看了就要有收穫,一起加油。
今天給大家分享的是大資料開發基礎部分MySQL的鎖,鎖在MySQL知識點中屬於比較重要的部分,大家一定要好好體會老劉的話,MySQL鎖篇的大綱如下:
看完老劉這篇內容後,希望你們能夠掌握以下內容:
MySQL的鎖分類 表級鎖中表鎖、後設資料鎖的原理 行鎖的原理、記錄鎖和間隙鎖的使用區別、死鎖的原理和死鎖場景
MySQL鎖介紹
為什麼有鎖?
多個程式對MySQL表或記錄進行訪問,就會產生競態條件,為了解決這個問題,就提出了鎖。
MySQL中的鎖如下圖:
MySQL表級鎖
表級鎖是由MySQL SQL layer層實現,只要鎖了一張表,只能對這張表操作。它有兩種:一是表鎖、二是後設資料鎖。
表鎖
表鎖有兩種表現形式:一是表共享讀鎖(Table Read Lock)、二是表獨佔寫鎖(Table Write Lock)。
我們採用手動增加表鎖,採用如下SQL語句:
lock table 表名稱 read(write),表名稱2 read(write),其他;
刪除表鎖,採用如下SQL語句:
unlock tables;
檢視錶鎖情況:
show open tables;
光說不練假把式,老劉用一個案例給各位夥伴好好講講表鎖,大家跟著一起練。
表鎖演示
--新建表
CREATE TABLE mylock (
id int(11) NOT NULL AUTO_INCREMENT,
NAME varchar(20) DEFAULT NULL,
PRIMARY KEY (id)
);
INSERT INTO mylock (id,NAME) VALUES (1, 'a');
INSERT INTO mylock (id,NAME) VALUES (2, 'b');
INSERT INTO mylock (id,NAME) VALUES (3, 'c');
INSERT INTO mylock (id,NAME) VALUES (4, 'd');
演示表讀鎖
1、我們先給表mylock加表讀鎖
session1: lock table mylock read;
2、加完表讀鎖後,session1還是能對該表進行查詢
session1: select * from mylock;
3、只要鎖了這張表,就只能先對這張表操作,不能訪問別的表,直到這張表被釋放。我用session1訪問表tdep就不能進行訪問,如圖:
4、雖然對這張表加鎖了,但我們別的session可以對它進行訪問。
session2:select * from mylock;
5、但如果session2要對mylock表進行修改,那就不行了,表讀鎖不允許加寫鎖,只允許加讀鎖,這也叫表共享讀。
session2:update mylock set name='x' where id=2;
6、這個時候session1釋放,session2才能進行修改。
session1:unlock tables;
session2:Rows matched: 1 Changed: 1 Warnings: 0 -- 修改執行完成
表讀鎖的內容就演示完了,現在開始演示表寫鎖的內容。
1、先給mylock加寫鎖
session1: lock table mylock write;
2、session1可以訪問mylock表,但不能訪問其他表。
3、session1也可以對該表進行修改,但是session2對該表進行讀取和修改就不行。
4、當session1釋放表寫鎖後,session2才能獲取。
session1:unlock tables;
session2:4 rows in set (41.65 sec)
通過這個例子,大家要明白讀鎖就是表共享讀鎖,自己可以用,其他人也可以訪問;寫鎖就是表獨佔寫鎖,意思就是隻有自己能夠訪問, 別的人不能訪問。
後設資料鎖
什麼是後設資料鎖?
後設資料,英語縮寫是MDL,在 MySQL 5.5 版本中引入了 MDL,當對一個表做增刪改查操作的時候,自動加 MDL 讀鎖;當要對錶做結 構變更操作的時候,自動加 MDL 寫鎖。
注意:這個鎖是自動提交的,要先開始事務,然後進行增刪改查時,會自動加MDL讀鎖。
現在開始後設資料鎖的演示,大家跟著老劉一起練習。
1、session1開啟事務,給表自動加讀鎖。
session1: begin;
select * from mylock;
2、session2對該表進行修改時就會造成阻塞。
session2: alter table mylock add f int;
3、session1提交事務 或者 rollback 釋放讀鎖 。
4、session2修改完成。
MySQL行級鎖
MySQL的行級鎖是由儲存引擎實現的,利用儲存引擎鎖住索引項來實現,主要講InnoDB行級鎖。
InnoDB行級鎖,按鎖範圍分為三種:
記錄鎖:鎖定索引中的一條記錄。 間隙鎖:鎖的是縫,要麼鎖住索引記錄中間的值,要麼鎖住第一個索引記錄前面的值或者最後一個索引記錄後面的值。 Next-key locks:記錄鎖和間隙鎖的組合(可以不看)
InnoDB行級鎖,按功能分:
共享讀鎖(S):手動新增,允許一個事務去讀一行,其他事務可以讀資料,但不能修改資料。
SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE -- 共享讀鎖 手動新增
排他寫鎖(X):自動新增,指的是一個事務在一行資料加上排他鎖後,其他事務不能再在其上加其他的鎖。
InnoDB也實現了表級鎖,也就是意向鎖,意向鎖是mysql內部使用的,不需要使用者干預。
兩階段鎖(2PL)
兩階段鎖講的是鎖操作分為兩個階段:加鎖階段和解鎖階段。
加鎖階段:只加鎖,不放鎖。
解鎖階段:只放鎖,不加鎖。
行鎖演示
InnoDB行鎖是通過給索引上的索引項加鎖來實現的,因此只有通過索引條件檢索的資料,InnoDB才會使用行級鎖,否則,InnoDB將使用表鎖!
行讀鎖
1、我們利用session1給id=1的行加讀鎖,使用索引。
session1: begin;
select * from mylock where ID=1 lock in share mode;
2、由於行鎖鎖定的是行,所以利用session2修改別的行例如id=2是可以的,修改id=1就不行了。
session2:update mylock set name='M' where id=2;
session2:update mylock set name='M' where id=1;
3、當session1提交後,session2才可以修改。
session1: commit;
session2:update mylock set name='M' where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
關於行鎖,我們要注意使用索引加行鎖 ,未鎖定的行可以訪問。
行讀鎖升級為表鎖
mylock表中id加了索引,name沒有加索引,當我們對name加行讀鎖時,就會出現行讀鎖升級為表鎖。
1、session1開啟事務
session1: begin;
2、手動加name='c'的行讀鎖,未使用索引
select * from mylock where name='c' lock in share mode;
3、session2修改阻塞,未用索引行鎖升級為表鎖
update mylock set name='N' where id=2;
4、session1提交事務或者 rollback 釋放讀鎖
commit;
5、session2就會修改成功
update mylock set name='N' where id=2;
行寫鎖
1、session1開啟事務並且手動加id=1的行寫鎖。
session1: begin;
select * from mylock where id=1 for update;
2、這裡有一個特別重要的知識點,很多人會弄錯!
排他鎖鎖住一行資料後,其他事務就不能讀取和修改該行資料,其實不是這樣的!
排他鎖指的是一個事務在一行資料加上排他鎖後,其他事務不能再在其上加其他的鎖。MySQL InnoDB引擎預設的修改資料語句:update,delete,insert都會自動給資料加上排他鎖,select語句預設不會加任何鎖型別,如果加排他鎖可以使用select …for update語句,加共享鎖可以使用select … lock in share mode語句。所以其他事務是不能修改加過排他鎖的資料行,其他事務也不能通過for update和lock in share mode鎖的方式查詢資料,但可以直接通過select …from…查詢資料,因為普通查詢沒有任何鎖機制。
所以session2可以訪問id=1的資料行。
session2: select * from mylock where id=1 ;
3、但是不能給它繼續加鎖
session2: select * from mylock where id=1 lock in share mode ;
4、session1提交事務或者rollback釋放寫鎖,session2才會執行成功
間隙鎖
根據檢索條件向左尋找最靠近檢索條件的記錄值A,作為左區間,向右尋找最靠近檢索條件的記錄值B作為右區間,即鎖定的間隙為(A,B)。根據圖中where number=5的話,那麼間隙鎖的區間範圍為(4,11);
間隙鎖防止兩種情況
防止插入間隙內的資料 防止已有資料更新為間隙內的資料
間隙情況:
id、number均在間隙內 id、number均在間隙外 id在間隙內、number在間隙外 id在間隙外,number在間隙內 id、number為邊緣資料
非唯一索引等值
update news set number=3 where number=4;
檢索條件number=4,向左取得最靠近的值2作為左區間,向右取得最靠近的5作為右區間,因此,session 1的間隙鎖的範圍(2,4),(4,5),即記錄(id=1,number=2)和記錄(id=3,number=4)之間間隙會被鎖定,記錄(id=3,number=4)和記錄(id=6,number=5)之間間隙被鎖定。
當我們新增資料時,結果如下:
insert into news value(2,3);
均在間隙內,阻塞
insert into news value(7,8);
均在間隙外,成功
insert into news value(2,8);
id在間隙內,number在間隙外,成功
insert into news value(4,8);
id在間隙內,number在間隙外,成功
insert into news value(7,3);
id在間隙外,number在間隙內,阻塞
insert into news value(7,2);
id在間隙外,number為上邊緣資料,阻塞
insert into news value(2,2);
id在間隙內,number為上邊緣資料,阻塞
insert into news value(7,5);
id在間隙外,number為下邊緣資料,成功
insert into news value(4,5);
id在間隙內,number為下邊緣資料,阻塞
我們可以得到只要number(where後面的)在間隙裡(2 3 4),不包含最後一個數(5)則不管id是多少都會阻塞。 如果是下邊緣資料需要看id是否在間隙內。
主鍵索引範圍
由於主鍵不能重複,所以id無邊緣資料。
update news set number=3 where id>1 and id <6;
insert into news value(2,3);
均在間隙內,阻塞
insert into news value(7,8);
均在間隙外,成功
insert into news value(2,8);
id在間隙內,number在間隙外,阻塞
insert into news value(4,8);
id在間隙內,number在間隙外,阻塞
insert into news value(7,3);
id在間隙外,number在間隙內,成功
我們可以得到只要id(在where後面的)在間隙裡(2 4 5),則不管number是多少都會阻塞。
非唯一索引無窮大
update news set number=3 where number=13 ;
insert into news value(11,5);
執行成功
insert into news value(12,11);
執行成功
insert into news value(14,11);
阻塞
insert into news value(15,12);
阻塞
檢索條件number=13,向左取得最靠近的值11作為左區間,向右由於沒有記錄因此取得無窮大作為右區間,因此,session 1的間隙鎖的範圍(11,無窮大),當id和number同時滿足 ,才會阻塞。
死鎖
兩個 session 互相等等待對方的資源釋放之後,才能釋放自己的資源,造成了死鎖,主要是順序出現問題。
我們session1先給id=1加鎖,session2再給id=2加鎖,此時session1想再給id=2加鎖,但session2已經給它加鎖了,就會造成死鎖。
如何解決死鎖?
MySQL預設會主動探知死鎖,並回滾某一個影響最小的事務,等待另一個事務執行完成之後,再重新執行該事務。
總結
本文作為大資料開發指南MySQL的第三篇詳細介紹了MySQL鎖的內容,希望大家能夠跟著老劉的文章,好好捋捋思路,爭取能夠用自己的話把這些知識點講述出來!
儘管當前水平可能不及各位大佬,但老劉會努力變得更加優秀,讓各位小夥伴自學從此不求人!
大資料開發指南地址如下:
github:https://github.com/BigDataLaoLiu/BigDataGuide 碼雲:https://gitee.com/BigDataLiu/BigDataGuide 如果有相關問題,聯絡公眾號:努力的老劉。文章都看到這了,點贊關注支援一波!