MySQL-lock(鎖)-v2.0
鎖
概念
對共享資源進行併發訪問
保證資料的完整性和一致性
每個資料庫的鎖的實現是完全不同的。在MySQL中:
MyISAM是表鎖
InnoDB是行級鎖(和Oracle SQL Server的行鎖不一樣 (SQL Server有頁級別的鎖))
區別
要注意資料庫中的鎖(lock)與程式中的鎖(latch)的區別:
Lock | Latch | |
---|---|---|
物件 | 事務 | 執行緒 |
保護 | 資料庫內容 | 記憶體資料結構 |
持續時間 | 整個事務過程 | 臨界資源 |
模式 | 行鎖,表鎖,意向鎖 | 讀寫鎖,互斥量 |
死鎖 | 通過waits-for graph(等待圖), time out 等機制進行死鎖檢測和分析 | 無死鎖檢測與處理機制。僅通過應用程式加鎖的順序保證無死鎖的情況發生。 |
存在 | Lock Manager的雜湊表中 | 每個資料結構的物件中 |
Tips:
- 在應用程式中,如果使用互斥量mutex和讀寫鎖rw-lock,有個原則是它持有的時間越短越好,如果持有的時間太長,那說明程式不好
- 進入臨界資源的時間應該越短越好,但資料庫中的鎖 鎖的是整個事務過程,鎖住的時間是根據事務時間而來的,資料庫中的鎖有 表鎖, 行鎖,意向鎖, 程式中的latch有讀寫鎖,互斥量, 應用程式中的latch沒有死鎖檢測。
MySQL中Latch的檢視:
mysql> show engine innodb mutex;
+--------+------------------------+---------+
| Type | Name | Status |
+--------+------------------------+---------+
| InnoDB | rwlock: log0log.cc:838 | waits=9 |
+--------+------------------------+---------+
1 row in set (0.10 sec)</pre>
Tips:通常來說,這些mutex沒有多大作用,主要是給核心DBA來看的。對於普通的DBA,要看的是資料庫中的鎖,Latch不是要關注的,只需要知道InnoDB也是有Latch的,因為一個程式肯定需要對共享資源進行併發 訪問,Latch是輕量級的鎖,持有的時間非常短,持有即釋放。
InnoDB中的鎖
S 行級共享鎖 表示可以併發進行訪問
X 行級排他鎖 有一個執行緒或會話佔用個這個行級別的鎖,那其他事務就不能去使用
IS意向S鎖 事務想要獲得一張表中某幾行的共享鎖
IX意向X鎖 事務想要獲得一張表中某幾行的排他鎖
AI(auto_increment)自增鎖 淘寶資料庫核心月報中關於這把鎖的介紹
Tips: 意向鎖揭示下一層級請求的鎖型別,即:下一層加一把什麼樣的鎖。 InnoDB儲存引擎中的意向鎖都是表鎖
各種鎖的相容性
相容: o(無需等待) 互斥:x(需等待) | s鎖 | x鎖 | ls鎖 | lx鎖 |
---|---|---|---|---|
s鎖 | o | x | o | x |
x鎖 | x | x | x | x |
ls鎖 | o | x | o | o |
lx鎖 | x | x | o | o |
意向鎖全部都是相容的(當前層是相容的,下一層再說),S和S鎖是相容的S和X鎖是不相容的。
如果表上加了一個X鎖,代表在表層級別進行加鎖,後面的執行緒都不能在下一層級別進行加鎖(IS,IX,S,X鎖都會發生等待)
資料庫加鎖過程是這樣的:
如果想對row_id=1
的記錄進行加鎖,就分別在庫,表,頁上加IS鎖,然後在記錄上加S鎖,加鎖時不是直接對記錄加鎖的,而是有一個樹的結構,對所有層次都進行加鎖,其他層次因為要加的不在它們上面,所以要加的不是S鎖,而是意向鎖,表示下一層級要加鎖的型別。
Q: 為什麼意向鎖之間是相互相容的
Q: 為什麼要設計意向鎖(為實現多粒度加鎖)
Q:為什麼不直接加鎖,而是有一個層級表示呢? 這是為了多層鎖的實現。
MySQL中沒有資料庫和頁級別的鎖,只有表鎖和記錄鎖,所以說,InnoDB中的意向鎖都是表鎖,加鎖都是從意向鎖開始加起的,不能直接加最低階別的鎖。
如果沒有意向鎖,現在想在表上加鎖,但是表鎖無法知道在下一層級記錄的情況.
如果沒有意向鎖機制,只有記錄鎖,那記錄鎖就是記錄鎖,如何實現表鎖呢?每一條記錄加鎖,但不能保證有其他事務在併發的使用這條記錄,不能實現表鎖。
鎖的資訊是儲存在記憶體中的。
innodb中的鎖都是表鎖,那給表加鎖時怎麼辦,直接加鎖嗎? 有些小小不一樣,mysql中的表鎖和innodb中的表鎖有些不一樣,通常來說,在innodb內部 通常不會在表級別加S,X鎖的. 加S鎖,在原始碼中有一個例子,加X鎖,在原始碼中沒有找到例子,什麼時候會在表級別加S鎖呢? 線上修改 (表鎖是在上層實現,不是在引擎層實現的)通常來說都是在表級別加意向鎖的,表級別是不會發生等待的,但是有種特別情況:alter table 並且要對錶加一個索引,add index建立索引的時候會對錶加一個S鎖,如果在加索引的過程中,有其他事務是IS鎖,要對一條記錄進行查詢,是可以執行的,但是如果有另外一個執行緒,執行要對記錄加X鎖的,S和IX在表層級互斥,就要發生等待 之前mysql加索引過程中,可以發現加索引對讀的操作是沒有影響的,但寫的事務就得等待了。這就是在innodb中,唯一在表級別加S鎖的情況:alter table add index . (因為索引要排序)
MySQL 如何加鎖
鎖的查詢:
> SHOW ENGINE INNODB STATUS;
mysql> desc lock_test_1;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| a | int(11) | NO | PRI | NULL | |
| b | int(11) | YES | | NULL | |
| c | int(11) | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
3 rows in set (0.00 sec)
mysql> select * from lock_test_1;
+---+------+------+
| a | b | c |
+---+------+------+
| 1 | 4 | 3 |
+---+------+------+
1 row in set (0.00 sec)
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from lock_test_1 where a = 1 for update; #加排它鎖
+---+------+------+
| a | b | c |
+---+------+------+
| 1 | 4 | 3 |
+---+------+------+
1 row in set (0.01 sec)
mysql> select * from lock_test_1 where a = 1 lock in share mode; #加共享鎖
mysql> pager less
mysql> show engine innodb status\G\c
...
---TRANSACTION 3353, ACTIVE 3045 sec
2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 9, OS thread handle 123145543925760, query id 133 localhost root
TABLE LOCK table `test_mysql`.`lock_test_1` trx id 3353 lock mode IX
RECORD LOCKS space id 46 page no 3 n bits 72 index PRIMARY of table `test_mysql`.`lock_test_1` trx id 3353 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 4; hex 80000001; asc ;; #記錄
1: len 6; hex 000000000d17; asc ;; #事務ID
2: len 7; hex b4000001280110; asc ( ;; #回滾指標
3: len 4; hex 80000004; asc ;; #記錄
4: len 4; hex 80000003; asc ;; #記錄
...
mysql> set global innodb_status_output_locks=1;
mysql> show variables like "%wait%timeout%";
+--------------------------+----------+
| Variable_name | Value |
+--------------------------+----------+
| innodb_lock_wait_timeout | 50 | # 鎖超時的設定變數(如果一個事務加不上鎖,會發生超時)
+--------------------------+----------+
3 rows in set (0.00 sec)
mysql5.6版本已經不會對錶加S鎖了,5.6出現online DDL功能的支援 對於很多DDL操作都是線上的了,讀寫都是可以的。
InnoDB有幾張源資料表(在information_schema中)儲存了事務和鎖的資訊
- innodb_trx(檢視執行的事務),
mysql> select * from innodb_trx\G
*************************** 1. row ***************************
trx_id: 3354
trx_state: RUNNING
trx_started: 2018-10-27 15:41:07
trx_requested_lock_id: NULL
trx_wait_started: NULL
trx_weight: 2
trx_mysql_thread_id: 10
trx_query: NULL
trx_operation_state: NULL
trx_tables_in_use: 0
trx_tables_locked: 1
trx_lock_structs: 2
trx_lock_memory_bytes: 1136
trx_rows_locked: 1
trx_rows_modified: 0
trx_concurrency_tickets: 0
trx_isolation_level: REPEATABLE READ
trx_unique_checks: 1
trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
trx_adaptive_hash_latched: 0
trx_adaptive_hash_timeout: 0
trx_is_read_only: 0
trx_autocommit_non_locking: 0
1 row in set (0.00 sec)</pre>
- innodb_locks(持有的鎖)
mysql> select * from innodb_locks\G
*************************** 1. row ***************************
lock_id: 3355:46:3:2
lock_trx_id: 3355
lock_mode: S
lock_type: RECORD
lock_table: `test_mysql`.`lock_test_1`
lock_index: PRIMARY
lock_space: 46
lock_page: 3
lock_rec: 2
lock_data: 1
*************************** 2. row ***************************
lock_id: 3354:46:3:2
lock_trx_id: 3354
lock_mode: X
lock_type: RECORD
lock_table: `test_mysql`.`lock_test_1`
lock_index: PRIMARY
lock_space: 46
lock_page: 3
lock_rec: 2
lock_data: 1
2 rows in set, 1 warning (0.00 sec)</pre>
- innodb_lock_waits(事務等待的事務)
mysql> melect * from innodb_lock_waits\G
*************************** 1. row ***************************
requesting_trx_id: 3355
requested_lock_id: 3355:46:3:2
blocking_trx_id: 3354
blocking_lock_id: 3354:46:3:2
1 row in set, 1 warning (0.00 sec)</pre>
建議用這三張表來檢視當前事務的鎖。(5.5 -5.6 版本中有的表)
SELECT
r.trx_id waiting_trx_id,
r.trx_mysql_thread_id waiting_thread,
r.trx_query waiting_query,
b.trx_id blocking_trx_id,
b.trx_mysql_thread_id blocking_thread,
b.trx_query blocking_query
FROM information_schema.innodb_lock_waits w INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id
INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id
*************************** 1. row ***************************
waiting_trx_id: 281479629835840
waiting_thread: 11
waiting_query: select * from lock_test_1 where a = 1 lock in share mode
blocking_trx_id: 3356
blocking_thread: 10
blocking_query: NULL
1 row in set, 1 warning (0.00 sec)
# 缺點:看不到阻塞的SQL語句
MySQL 5.6開始還有個更牛逼的元資訊庫:
mysql> select * from innodb_lock_waits\G
*************************** 1. row ***************************
wait_started: 2018-10-27 16:12:42
wait_age: 00:00:09
wait_age_secs: 9
locked_table: `test_mysql`.`lock_test_1`
locked_index: PRIMARY # InnoDB 的鎖都是在索引上面
locked_type: RECORD
waiting_trx_id: 281479629835840
waiting_trx_started: 2018-10-27 16:12:42
waiting_trx_age: 00:00:09
waiting_trx_rows_locked: 1
waiting_trx_rows_modified: 0
waiting_pid: 11
waiting_query: select * from lock_test_1 where a = 1 lock in share mode
waiting_lock_id: 281479629835840:46:3:2
waiting_lock_mode: S
blocking_trx_id: 3356
blocking_pid: 10
blocking_query: NULL
blocking_lock_id: 3356:46:3:2
blocking_lock_mode: X
blocking_trx_started: 2018-10-27 16:08:16
blocking_trx_age: 00:04:35
blocking_trx_rows_locked: 1
blocking_trx_rows_modified: 0
sql_kill_blocking_query: KILL QUERY 10
sql_kill_blocking_connection: KILL 10
1 row in set, 3 warnings (0.01 sec)</pre>
遺憾的是在MySQL中,鎖的歷史資訊是看不到的。
鎖與事務隔離級別
先看四個概念:
locking
concurrency control
isolation
serializability
這四個概念在資料庫中是一個概念:鎖是用來實現併發控制的,併發控制用來實現隔離級別,同樣隔離級別是通過鎖來控制的,而鎖的目的是為了使得事務之間的執行時序列化的(序列化)。
併發控制準則:併發不能導致程式出錯, 不能導致吞吐率降低或者響應時間更快(Concurrent execution should not have lower throughput or much higher response times than serial execution.)
事務隔離級別
隔離性 : 多個事務並行執行,好似是序列執行的;一個事務所做的修改對其他事務是不可見的,好似是序列執行的。
事務隔離級別有四種:
READ UNCOMMITTED
-
READ COMMITTED
- Oracle、DB2、SQL Server的預設事務隔離級別...
REPEATABLE READ
SERIALIZABLE
Oracle支援SERIALIZABLE和READ COMMITTED
SQL Server 和 MySQL四個級別都支援
但這樣沒有解決事務可能存在的問題,如:
在不同的事務隔離級別下,存在不同的問題:如:不可重複讀, 幻讀,髒讀.
髒讀 : 能讀到未提交事務的狀態.
不可重複讀:一個事務裡執行兩條相同的sql 對同一記錄執行結果不同
幻讀( phantom read) 連續執行兩次同樣的SQL語句可能導致不同的結果,第二次的SQL語句可能會返回之前不存在的行
在標準的事務隔離級別中:
READ UNCOMMITTED 三種問題都存在
READ COMMITTED 解決了髒讀問題
REPEATABLE READ 解決了髒讀和不可重複讀問題
SERIALIZABLE 是標準的隔離級別,解決了髒讀,幻讀,不可重複讀 問題。
MySQL的InnoDB在RR級別解決了幻讀問題(使用了next-key lock algorithm)。
舉例:
# 首先檢視事務隔離級別
mysql> select @@global.transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-UNCOMMITTED |
+-------------------------+
1 row in set (0.00 sec)
select @@global.tx_isolation, @@tx_isolation; </pre>
髒讀
在一個session中,顯示:
在另一個程式中,開啟一個事務:
未提交的資料,另一個session卻可以讀到:
髒讀 : 能讀到未提交事務的狀態.
不可重複讀:
一個session中:
此時在另一個session中:
此時在第一個session中:
不可重複讀:一個事務裡執行一條相同的sql對同一記錄執行結果不同
幻讀
一個事務中:連續執行兩次 select * from t where a <= 30 for update
會得到不同的結果
幻讀( phantom read) 連續執行兩次同樣的SQL語句可能導致不同的結果,第二次的SQL語句可能會返回之前不存在的行
比如:
事務1: SELECT*FROM tb_a WHERE A<=13; 對於READ COMMITTED,返回的是10,11,13 此時事務2 插入12,再執行sql語句,得到的是10,11,12,13,兩次返回的結果不同,12是之前沒有的,這就叫做幻讀,在InnnoDB中,鎖住的是(-∞,10],(10,11],(11,13]這三個範圍。 事務2要想插入,需要等待,這樣就解決了幻讀,第二次執行SELECT也不會有12這條記錄
但是這樣是有代價的:併發度低。12這條記錄不能插入了,要獲得更大的併發性,可以把隔離級別調成READ COMMITTED
記錄鎖的型別
-
Record Lock
- 單個行記錄上的鎖
-
Gap Lock
- 鎖定一個範圍,但不包含記錄本身
-
Next-key Lock
- Gap Lock + Record Lock,鎖定一個範圍,並且鎖定記錄本身
舉例:
假設有 id 為 10 20 30 的幾條記錄
- Record Lock:之鎖住10 20 30 這些記錄本身。
- Gap Lock:當鎖10時,鎖住的是(-∞,10) 這樣的一個範圍,鎖20時,鎖的是 (10,20)以此類推
- Next-key Lock:是前面兩個演算法的結合,當鎖10時,鎖住的是(-∞,10],鎖20時,鎖的是(10,20], 鎖住20本身,是不能對其進行update or delete 操作,而Gap 鎖不鎖定記錄本身,可以對其進行這些操作。
mysql> desc t;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| a | int(11) | NO | PRI | NULL | |
+-------+---------+------+-----+---------+-------+
1 row in set (0.00 sec)
mysql> insert into t values (10), (20), (30), (40);
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> delete from t where a<= 30;
Query OK, 3 rows affected (0.00 sec)
---TRANSACTION 3440, ACTIVE 35 sec
2 lock struct(s), heap size 1136, 3 row lock(s), undo log entries 3
MySQL thread id 13, OS thread handle 123145543925760, query id 569 localhost root
TABLE LOCK table `test_mysql`.`t` trx id 3440 lock mode IX
RECORD LOCKS space id 47 page no 3 n bits 72 index PRIMARY of table `test_mysql`.`t` trx id 3440 lock_mode X locks rec but not gap # record lock
Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 32
0: len 4; hex 8000000a; asc ;; # 10
1: len 6; hex 000000000d70; asc p;;
2: len 7; hex 4f000001850110; asc O ;;
Record lock, heap no 3 PHYSICAL RECORD: n_fields 3; compact format; info bits 32
0: len 4; hex 80000014; asc ;; # 20
1: len 6; hex 000000000d70; asc p;;
2: len 7; hex 4f000001850132; asc O 2;;
Record lock, heap no 4 PHYSICAL RECORD: n_fields 3; compact format; info bits 32
0: len 4; hex 8000001e; asc ;; # 30
1: len 6; hex 000000000d70; asc p;;
2: len 7; hex 4f000001850154; asc O T;;</pre>
mysql> select @@global.tx_isolation, @@tx_isolation;
+-----------------------+-----------------+
| @@global.tx_isolation | @@tx_isolation |
+-----------------------+-----------------+
| REPEATABLE-READ | REPEATABLE-READ |
+-----------------------+-----------------+
mysql> select * from t;
+----+
| a |
+----+
| 10 |
| 20 |
| 30 |
| 40 |
+----+
4 rows in set (0.00 sec)
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t where a <= 30 for update;
+----+
| a |
+----+
| 10 |
| 20 |
| 30 |
+----+
3 rows in set (0.00 sec)
mysql> insert into t select 15;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
insert into t select 15
------- TRX HAS BEEN WAITING 7 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 47 page no 3 n bits 72 index PRIMARY of table `test_mysql`.`t` trx id 3485 lock_mode X locks **gap before rec insert intention waiting**
Record lock, heap no 3 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 4; hex 80000014; asc ;;
1: len 6; hex 000000000d95; asc ;;
2: len 7; hex e40000018f011c; asc ;;
------------------
TABLE LOCK table `test_mysql`.`t` trx id 3483 lock mode IX RECORD LOCKS space id 47 page no 3 n bits 72 index PRIMAR Y of table `test_mysql`.`t` trx id 3483 lock_mode X
Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 4; hex 8000000a; asc ;;
1: len 6; hex 000000000d95; asc ;;
2: len 7; hex e40000018f0110; asc ;;
Record lock, heap no 3 PHYSICAL RECORD: n_fields 3; compa
ct format; info bits 0
0: len 4; hex 80000014; asc ;;
1: len 6; hex 000000000d95; asc ;;
2: len 7; hex e40000018f011c; asc ;;
Record lock, heap no 4 PHYSICAL RECORD: n_fields 3; compa
ct format; info bits 0
0: len 4; hex 8000001e; asc ;;
1: len 6; hex 000000000d95; asc ;;
2: len 7; hex e40000018f0128; asc (;;
Record lock, heap no 5 PHYSICAL RECORD: n_fields 3; compa
ct format; info bits 0
0: len 4; hex 80000028; asc (;;
1: len 6; hex 000000000d95; asc ;;
2: len 7; hex e40000018f0134; asc 4;;
# RR事務隔離級別:遊標掃記錄,直到第一條不符合要求的記錄都加鎖
MySQL預設的事務隔離級別(RR)用的是Next-key locking演算法
Next-key lock優化成record lock 的條件:
鎖定一條記錄,鎖定的這條記錄的索引包含唯一索引
Gap locking is not needed for statements that lock rows using a unique index to search for a unique row. (This does not include the case that the search condition includes only some columns of a multiple-column unique index; in that case, gap locking does occur.)
RECORD LOCKS space id 47 page no 3 n bits 72 index PRIMAR
Y of table `test_mysql`.`t` trx id 3487 lock_mode **X locks
rec but not gap**
Record lock, heap no 3 PHYSICAL RECORD: n_fields 3; compa
ct format; info bits 0
0: len 4; hex 80000014; asc ;;
1: len 6; hex 000000000d95; asc ;;
2: len 7; hex e40000018f011c; asc ;;</pre>
Q:為什麼要有隔離性呢?
A: 如果沒有隔離性,一個事務del <= 7; 另一個事務在中間 INS 6;
事務 | Tx1 | Tx2 |
---|---|---|
BEGIN | ||
del <= 10 | ||
BEGIN | ||
INS 5 | ||
COMMIT | ||
COMMIT |
這個表裡最後還剩5
但是在log裡記錄的其實是:
insert
delete
如果從機用這個日誌去備份,會有主從不一致
舉例
例子:
對Z表插入了這些資料
CREATE TABLE z ( a INT, b INT, PRIMARY KEY(a), KEY(b) );
INSERT INTO z SELECT 1,1;
INSERT INTO z SELECT 3,1;
INSERT INTO z SELECT 5,3;
INSERT INTO z SELECT 7,6;
INSERT INTO z SELECT 10,8;
一個事務執行:
BEGIN;
SELECT * FROM z WHERE b=3 FOR UPDATE;
Q: # 在RR隔離級別下,以下哪些能執行,哪些不能執行呢?
a: 1 3 5 7 10
b: 1 1 3 6 8
a: 5 X record鎖
b: (1:3] ,(3,6) X gap鎖
SELECT * FROM z WHERE a = 5 LOCK IN SHARE MODE; # 是給a加S鎖,前面加了X鎖,不行
INSERT INTO z SELECT 4,2; # b=2,在(1,3]範圍之內,也不行
INSERT INTO z SELECT 6,5; #不能插入 其實b還有一個GAP鎖,範圍是(3,6),如果鎖是二級索引,且非唯一,那麼就會有一個隱含的GAP鎖。
INSERT INTO z SELECT 8,6; # OK 6不屬於(3,6)返回,會加到原來的記錄後面
INSERT INTO z SELECT 2,0; # OK
INSERT INTO z SELECT 6,7; # OK
# 如果不鎖住(3,6),就可以插入(6,3) 如果再返回記錄b=3 ,那返回的就是(5,3),(6,3)
注意:這裡的中括號不是數學上的概念,如果新插入的是3,原來是(1,3] 還是能插入3的,是(3,3],它在原範圍之後的,不是之內,所以不鎖住這個範圍,就會有幻讀問題。
InnoDB預設使用Next-key lock algorithm,他鎖住的是前面記錄和當前記錄的範圍,若鎖住了13這條記錄,那12這條記錄是插入不進來的,這樣就解決了幻讀問題。
某些情況下,可以將Next-key lock 降解成Record Lock,從而獲得併發性。什麼情況呢? 當索引含有唯一約束 並且鎖定的是一條記錄,這時就可以只鎖住事務本身。 上面的例子:如果10,11,13,20是PK,意味著unique,如果SELECT PK=10,只鎖定一條記錄,那它鎖住的就是10本身,而不是(-∞,10)這樣的範圍,但是如果條件是<=10;那鎖定的還是 (-∞,10]這樣的範圍,記錄索引是唯一 一條而不是一個範圍)的話,鎖定1條記錄( point select),就不需要使用範圍鎖了。不管事務是序列還是並行執行的,得到的結果都是一致的。
隔離性越高,持有鎖的時間越長,併發性越差。
隔離級別與鎖的問題
RR -> next-key lock
RC -> record lock
對於沒有索引的表,選一個記錄進行刪除時。RR 時,鎖的是全部記錄,RC時,鎖的是一條記錄。
鎖重用
結果:鎖開銷進一步下降
BEGIN;
SELECT * FROM t WHERE rowid = xxx FOR UPDATE;
SELECT * FROM t WHERE rowid = yyy FOR UPDATE;
BEGIN;
SELECT * FROM t WHERE rowid = xxx FOR UPDATE;
SELECT * FROM t WHERE rowid = xxx LOCK IN SHARE MODE;
隱式鎖
開啟一個事務,當插入一條記錄時候,看不到鎖,但是當另一個事務想要對這條記錄加鎖時就會出現。
Q : 那如何知道這條記錄有沒有隱式鎖呢? 可以通過事務id來判斷
所以,在插入的過程中,多個事務可以並行執行。
鎖定讀:
select * from a where c = 1 for update/lock in share mode
但是一般我們用的是:
select * from a where c = 1
在事務隔離級別<= RR的情況下,這樣的讀是非鎖定讀(及時記錄被更新,也能被讀取,讀不會被阻塞,這是通過行多版本來實現的),這行資料是否被更新 可以通過事務id來確認(如果被更新,就讀之前的版本)。
死鎖
資料庫中的死鎖有死鎖檢測機制,可以死鎖檢測把死鎖回滾掉
兩個或兩個以上的事務在執行過程中 因爭奪鎖資源而造成的一種互相等待的現象
AB-BA
解決死鎖
超時 • --innodb_lock_timeout
wait-for graph • 自動死鎖檢測
當資料庫檢測到死鎖時,會自動回滾事務,釋放持有的鎖。
死鎖檢視: show engine innodb status\G LATEST DETECTED DEAFLOCK 會顯示最近的死鎖 5.6有一個引數: innodb_print_all_deadlocks=OFF 把這個引數設定為1,只要發生死鎖,就會把死鎖資訊寫到錯誤檔案裡面, 這時候,檢視錯誤日誌就能看到所有的死鎖的資訊。
InnoDB鎖的演算法:
在InnoDB中,鎖是通過點陣圖來實現的,用點陣圖來儲存哪些記錄有鎖,儲存時不是以記錄為單位的,而是根據一個頁,一個頁中有多少條記錄,然後看看這些記錄哪些上鎖了,在記憶體中,有這樣一個區域,用點陣圖的方式記錄一個頁裡 哪些記錄有鎖。
相關文章
- Cloudarrow V2.0 正式釋出!Cloud
- promise v2.0版本Promise
- 如何使用新版 API v2.0API
- AutoHotKey v2.0 定義快捷鍵
- 青春部落格-V2.0版本
- Wemall團購版更新V2.0版
- 帶你全面認識CMMI V2.0(二)
- MySQL鎖(讀鎖、共享鎖、寫鎖、S鎖、排它鎖、獨佔鎖、X鎖、表鎖、意向鎖、自增鎖、MDL鎖、RL鎖、GL鎖、NKL鎖、插入意向鎖、間隙鎖、頁鎖、悲觀鎖、樂觀鎖、隱式鎖、顯示鎖、全域性鎖、死鎖)MySql
- EMQ 文件 V1.0 V2.0 V3.0MQ
- Mojito Admin v2.0 的一些變化
- DataWorks資料服務V2.0全新發布
- AirNet系統扇區修改說明.V2.0AI
- 剪下板管理神器:Clipsy for mac v2.0啟用版Mac
- battery-historian v2.0 環境搭建 --- 2020/10/01BAT
- 貼貼笑話網站 手機端 V2.0網站
- ExtAspNet釋出新版本 - v2.0 beta3
- 帶你全面認識CMMI V2.0(六)——改進
- 自旋鎖、阻塞鎖、可重入鎖、悲觀鎖、樂觀鎖、讀寫鎖、偏向所、輕量級鎖、重量級鎖、鎖膨脹、物件鎖和類鎖物件
- Java鎖?分散式鎖?樂觀鎖?行鎖?Java分散式
- Java鎖最全詳解:樂觀鎖/悲觀鎖+公平鎖/非公平鎖+獨享鎖/共享鎖Java
- Java 中15種鎖的介紹:公平鎖,可重入鎖,獨享鎖,互斥鎖,樂觀鎖,分段鎖,自旋鎖等等Java
- 全域性鎖、表鎖、行鎖
- MySQL鎖(樂觀鎖、悲觀鎖、多粒度鎖)MySql
- java 中的鎖 -- 偏向鎖、輕量級鎖、自旋鎖、重量級鎖Java
- InnoDB常用鎖總結(行鎖、間隙鎖、臨鍵鎖、表鎖)
- C# 離線人臉識別 ArcSoft V2.0 DemoC#
- 【開源】夢雪實體小店收款系統 v2.0
- 道法術器 — DevOps 端到端部署流水線 V2.0dev
- 感知器演算法及其python 實現 V2.0演算法Python
- NGMN:解耦網路白皮書v2.0(附下載)解耦
- 帶你全面認識CMMI V2.0(終)——實施落地
- 帶你全面認識CMMI V2.0(四)——管理 賦能
- MySQL/InnoDB中,樂觀鎖、悲觀鎖、共享鎖、排它鎖、行鎖、表鎖、死鎖概念的理解MySql
- mysql鎖之死鎖MySql
- 【鎖】Oracle鎖系列Oracle
- 聚微商高階貨源平臺原始碼V2.0原始碼
- AndPHP.admin V2.0 純淨版(免費切開源)PHP
- Sketch和AE可以對接啦-Sketch2AE v2.0