[msyql]-鎖機制
阿新 • • 發佈:2020-09-20
概述
定義
鎖是計算機協調多個程序或執行緒併發訪問某一資源的機制。
在資料庫中,傳統的計算機資源(CPU、IO、RAM)的爭用外,資料也是一種供許多使用者共享的資源。如何保證資料併發的訪問的一致性、有效性是所有的資料庫必須解決的一個問題,鎖衝突也是資料庫併發訪問的效能的一個重要因素。從這個角度來說,鎖是對資料庫而言顯的尤為重要,也更加複雜。
鎖的分類
從對資料操作的型別(讀/寫)分
- 讀鎖(共享鎖):針對同一份資料,多個讀操作可以統一同時進行而不會互相影響。
- 寫鎖(排他鎖):當親寫操作沒有完成前,它會阻斷其他寫鎖客讀鎖。
從資料操作的粒度分
- 表鎖
- 行鎖
表鎖(便讀)
特點
偏向MyISAM儲存引擎,開銷小,加鎖快;無死鎖;鎖定粒度大,發生鎖衝突的概率最高,併發度最低。
案例分析
建表SQL
create table mylock ( id int not null primary key auto_increment, name varchar(20) default '' ) engine myisam; insert into mylock(name) values('a'); insert into mylock(name) values('b'); insert into mylock(name) values('c'); insert into mylock(name) values('d'); insert into mylock(name) values('e'); select * from mylock;
表鎖命令
#查看錶上加過的鎖
show open tables;
#給mylock上讀鎖,給book上寫鎖
lock table my lock read, book write;
#釋放表鎖
unlock tables;
讀鎖案例
- 加讀鎖,為mylock表加read鎖
#開啟兩個mysql會話
#會話1
#為mylock加鎖(讀)
lock table mylock read;
#會話1(可以讀不可寫) update mylock set name='a2' where id = 1; ERROR 1099 (HY000): Table 'mylock' was locked with a READ lock and can't be updated #會話1,中mylock上 read 期間,其他表不可以讀 mysql> select * from book; ERROR 1100 (HY000): Table 'book' was not locked with LOCK TABLES
#會話2
#在會話1對mylock上 read 期間可以讀mylock與其他表
#會話2
#在會話1對mylock上 read 期間可以需要 會話1 解鎖 才能對mylock進行修改
總結(讀鎖)
寫鎖案例
- 在會話1中新增寫鎖
mysql> LOCK TABLE `mylock` WRITE;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from mylock;
+----+------+
| id | name |
+----+------+
| 1 | a3 |
| 2 | b |
| 3 | c |
| 4 | d |
| 5 | e |
+----+------+
5 rows in set (0.00 sec)
mysql> update mylock set name='a4' where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
#不能讀其他表
mysql> select * from book;
ERROR 1100 (HY000): Table 'book' was not locked with LOCK TABLES
- 會話2
#阻塞了,需要會話一釋放鎖
mysql> select * from mylock;
總結(寫鎖)
案例總結
MyISAM
引擎在執行查詢語句SELECT
之前,會自動給涉及到的所有表加讀鎖,在執行增刪改之前,會自動給涉及的表加寫鎖。
MySQL的表級鎖有兩種模式:
-
表共享讀鎖(Table Read Lock)。
-
表獨佔寫鎖(Table Write Lock)。
対MyISAM
表進行操作,會有以下情況:
- 対
MyISAM
表的讀操作(加讀鎖),不會阻塞其他執行緒対同一表的讀操作,但是會阻塞其他執行緒対同一表的寫操作。只有當讀鎖釋放之後,才會執行其他執行緒的寫操作。 - 対
MyISAM
表的寫操作(加寫鎖),會阻塞其他執行緒対同一表的讀和寫操作,只有當寫鎖釋放之後,才會執行其他執行緒的讀寫操作。
簡而言之,就是讀鎖會阻塞寫,但是不會阻塞讀。而寫鎖會把讀和寫都阻塞。
分析
-
看看哪些表被鎖了
show open tables; -
如何分析表鎖定
SHOW STATUS LIKE 'table%';
可以通過Table_locks_immediate
和Table_locks_waited
狀態變數來分析系統上的表鎖定。
Table_locks_immediate
:產生表級鎖定的次數,表示可以立即獲取鎖的查詢次數,每立即獲取鎖值加1。
Table_locks_waited
:出現表級鎖定爭用而發生等待的次數(不能立即獲取鎖的次數,每等待一次鎖值加1),此值高則說明存在較嚴重的表級鎖爭用情況。
此外,MyISAM
的讀寫鎖排程是寫優先,這也是MyISAM
不適合作為主表的引擎。因為寫鎖後,其他執行緒不能進行任何操作,大量的寫操作會使查詢很難得到鎖,從而造成永遠阻塞。
行鎖(偏寫)
特點
- 偏向InnoDB儲存引擎,開銷大,加鎖慢:會出現死鎖;鎖粒度最小,發生鎖衝突的概率最低,併發度也最高。
- InnoDB與MyISAM的最大不同有兩點:一是支援事務(TRANSACTION);二是採用了行級鎖
併發事務帶來的問題
- 更新丟失
當兩個或多個事務選擇同一行,然後基於最初選定的值更新該行時,由於每個事務都不知道其他事務的存在,就會發生丟失更新題--最後的更新覆蓋了由其他事務所做的更新。
例如,兩個程式設計師修改同一java檔案。每程式設計師獨立地更改其副本,然後儲存更改後的副本,這樣就覆蓋了原始文件。最後儲存其更改副本的編輯人員覆蓋前一個程式設計師所做的更改。
如果在一個程式設計師完成並提交事務之前,另一個程式設計師不能訪問同一檔案,則可避免此問題。
- 髒讀
- 不可重複復
- 幻讀
事務隔離級別
行鎖案例
建表sql
CREATE TABLE test_innodb_lock (a INT(11),b VARCHAR(16))ENGINE=INNODB;
INSERT INTO test_innodb_lock VALUES(1,'b2');
INSERT INTO test_innodb_lock VALUES(3,'3');
INSERT INTO test_innodb_lock VALUES(4, '4000');
INSERT INTO test_innodb_lock VALUES(5,'5000');
INSERT INTO test_innodb_lock VALUES(6, '6000');
INSERT INTO test_innodb_lock VALUES(7,'7000');
INSERT INTO test_innodb_lock VALUES(8, '8000');
INSERT INTO test_innodb_lock VALUES(9,'9000');
INSERT INTO test_innodb_lock VALUES(1,'b1');
CREATE INDEX test_innodb_a_ind ON test_innodb_lock(a);
CREATE INDEX test_innodb_lock_b_ind ON test_innodb_lock(b);
set autocommit=0;
讀己知所寫
# 會話1
# 會話1対test_innodb_lock表做寫操作,但是沒有commit。
# 執行修改SQL之後,查詢一下test_innodb_lock表,發現數據被修改了。
mysql> UPDATE `test_innodb_lock` SET `b` = '88' WHERE `a` = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> SELECT * FROM `test_innodb_lock`;
+------+------+
| a | b |
+------+------+
| 1 | 88 |
| 2 | 3 |
| 3 | 4000 |
| 4 | 5000 |
| 5 | 6000 |
| 6 | 7000 |
| 7 | 8000 |
| 8 | 9000 |
+------+------+
8 rows in set (0.00 sec)
# 會話2
# 會話2這時候來查詢test_innodb_lock表。發現會話2是讀不到SESSION1未提交的資料的。
mysql> SELECT * FROM `test_innodb_lock`;
+------+------+
| a | b |
+------+------+
| 1 | b2 |
| 2 | 3 |
| 3 | 4000 |
| 4 | 5000 |
| 5 | 6000 |
| 6 | 7000 |
| 7 | 8000 |
| 8 | 9000 |
+------+------+
8 rows in set (0.00 se
兩個回話同時更新同一條資料
兩個回話同時更新不同行資料
回話之間互不影響