溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

MySQL中的鎖和事務(wù)隔離級別是什么

發(fā)布時間:2020-06-23 12:13:23 來源:億速云 閱讀:270 作者:Leah 欄目:MySQL數(shù)據(jù)庫

MySQL中的鎖和事務(wù)隔離級別是什么?可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

數(shù)據(jù)庫的鎖機制是區(qū)別于文件系統(tǒng)的一個關(guān)鍵特性。用于管理對共享資源的并發(fā)訪問。InnoDB會在很多地方使用鎖機制,比如操作緩沖池中的數(shù)據(jù)表、LRU頁列表、數(shù)據(jù)行,為了保證一致性和完整性,需要有鎖的機制。

對于不同數(shù)據(jù)庫,鎖機制的設(shè)計和實現(xiàn)完全不同:

 ● MyISAM引擎: 表鎖設(shè)計,并發(fā)讀沒有問題,并發(fā)寫性能差。

 ● Microsoft SQL Server: 支持樂觀并發(fā)和悲觀并發(fā),樂觀并發(fā)下支持行級鎖,維持鎖的開銷大,在行鎖數(shù)量超過閾值后會升級為表鎖。

 ● InnoDB引擎: 支持行鎖,提供一致性的非鎖定讀。行鎖沒有額外開銷,性能不會下降。

 ● Oracle:和InnoDB引擎非常類似。

兩類鎖:lock和latch

數(shù)據(jù)庫中l(wèi)ock和latch都可以稱為鎖,但是有很大的區(qū)別。

latch一般稱為閂鎖,用于保證并發(fā)線程操作臨界資源的正確性,作用對象是內(nèi)存數(shù)據(jù)結(jié)構(gòu),要求鎖定時間非常短,不會檢測死鎖。在InnoDB引擎中又分為mutex(互斥量)和rwlock(讀寫鎖)。

lock是用來鎖定數(shù)據(jù)庫中的對象,如表、頁、行,作用對象是事務(wù),在commit/rollback后釋放,會檢測死鎖。分為行鎖、表鎖、意向鎖。

我們下面的鎖指的都是lock類鎖。

四種鎖類型

InnoDB支持四種鎖:

 ● 共享鎖(S Lock):允許事務(wù)讀一行數(shù)據(jù)

 ● 排他鎖(X Lock):允許事務(wù)刪除或更新一行數(shù)據(jù)

 ● 意向共享鎖(Intention S Lock):事務(wù)想要獲得一張表中某幾行的共享鎖

 ● 意向排他鎖(Intention X Lock):事務(wù)想要獲得一張表中某幾行的排他鎖

當事務(wù)T1獲取了行r的共享鎖,由于讀取不會改變行數(shù)據(jù),因此事務(wù)T2也可以直接獲得行r的共享鎖,此時稱為鎖兼容(Lock Compatible)。

而當事務(wù)T3想要獲取行r的排他鎖進行修改數(shù)據(jù)時,就需要等待T1/T2釋放行共享鎖,此時稱為鎖不兼容。

S鎖和X鎖都是行鎖,而IS鎖和IX鎖都為意向鎖,屬于表鎖。意向鎖的設(shè)計是為了在一個事務(wù)中揭示下一行將被請求的鎖類型,即在表鎖的更細粒度進行鎖定。由于InnoDB支持表鎖,因此意向鎖不會阻塞除全表掃描外的任何請求。

鎖的兼容性:


ISIXSX
IS兼容兼容兼容不兼容
IX兼容兼容不兼容不兼容
S兼容不兼容兼容不兼容
X不兼容不兼容不兼容不兼容

存儲事務(wù)和鎖信息的三張表

我們可以通過show engine innodb status命令在事務(wù)部分查看當前鎖請求的信息。

從InnoDB1.0開始,在INFORMATION_SCHEMA架構(gòu)下添加了INNODB_TRX(transaction事務(wù)表)、INNODB_LOCKS(鎖表)、INNODB_LOCK_WAITS(鎖等待表),通過這三張表,可以讓我們實時監(jiān)控當前事務(wù)并分析可能存在的表問題。

三個表的定義分別為:

INNODB_TRX
trx_idInnoDB存儲引擎內(nèi)部唯一的事務(wù)ID
trx_state當前事務(wù)的狀態(tài)
trx_started事務(wù)的開始時間
trx_requested_lock_id等待事務(wù)的鎖IDC,當狀態(tài)不為LOCK WAIT時為NULL
trx_wait_started事務(wù)等待開始的時間
trx_weight事務(wù)的權(quán)重,反映一個事務(wù)修改和鎖定的行數(shù)。當需要回滾時,選擇該值最小的事務(wù)進行回滾
trx_mysql_thread_idMySQL的線程ID,show processlist顯示的結(jié)果
trx_query事務(wù)運行的SQL語句
INNODB_LOCKS
lock_id鎖ID
lock_trx_id事務(wù)ID
lock_mode鎖的模式
lock_type鎖的類型,表鎖或行鎖
lock_table要加鎖的表
lock_index鎖住的索引
lock_space鎖對象的space id
lock_page事務(wù)鎖定頁的數(shù)量,表鎖時為NULL
lock_rec事務(wù)鎖定行的數(shù)量,表鎖時為NULL
lock_data事務(wù)鎖定記錄的主鍵值,表鎖時為NULL
INNODB_LOCK_WAITS
requesting_trx_id申請鎖資源的事務(wù)ID
requesting_lock_id申請的鎖的ID
blocking_trx_id阻塞的事務(wù)ID
blocking_lock_id阻塞的鎖的ID

通過INNODB_TRX我們可以看到所有的事務(wù),以及事務(wù)是否被阻塞,阻塞的鎖ID是什么。
之后,通過INNODB_LOCKS查看所有的鎖信息。
之后,通過INNODB_LOCK_WAITS可以查看到鎖的等待信息以及阻塞關(guān)系。

通過這三種表能夠較為清晰的查看事務(wù)和鎖的情況,也可以聯(lián)合查詢,在下面的一些場景下我們會來展示這三個表的內(nèi)容。

隔離級別

首先我們來說下數(shù)據(jù)庫的四種事務(wù)隔離級別:

 ● READ UNCOMMITTED(0): 瀏覽訪問級別,存在臟讀、不可重復(fù)讀、幻讀

 ● READ COMMITTED(1): 游標穩(wěn)定級別,存在不可重復(fù)度、幻讀

 ● REPEATABLE READ(2): 存在幻讀

 ● SERIALIZABLE(3): 隔離級別,保證事務(wù)安全,但完全串行,性能低

這四種事務(wù)隔離級別是指定的SQL標準,InnoDB默認的隔離級別是REAPEATABLE READ,但與其他數(shù)據(jù)庫不同的時,它同時使用了Next-Key-Lock鎖的算法,能夠避免幻讀的產(chǎn)生,因此能夠完全滿足事務(wù)的隔離性要求,即達到SERIALIZABLE隔離級別。

隔離級別越低,事務(wù)請求的鎖越少或持鎖時間越短,因此大部分數(shù)據(jù)庫的默認隔離級別為READ COMMITED。但是有相關(guān)的分析也指出,隔離級別的性能開銷幾乎一樣,因此用戶無須通過調(diào)整隔離級別來提高性能。

查看和修改事務(wù)隔離級別的命令:

mysql> select @@session.tx_isolation;
+------------------------+
| @@session.tx_isolation |
+------------------------+
| REPEATABLE-READ        |
+------------------------+
1 row in set (0.00 sec)

mysql> set session transaction isolation level SERIALIZABLE;
Query OK, 0 rows affected (0.00 sec)

示例中修改了本次會話的事務(wù)隔離級別,如果需要修改全局參數(shù),可以替換session為global。如果想要永久修改,需要修改配置文件:

[mysqld]
transaction-isolation = READ-COMMITED

在SERIALIZABLE的事務(wù)隔離級別,InnoDB會對每個SELECT語句后自動加上LOCK IN SHARE MODE,來對讀操作加上一個共享鎖,因此不再支持一致性的非鎖定讀。

由于InnoDB在REPEATABLE READ隔離級別就可以達到SERIALIZABLE,因此一般不用使用最高隔離級別。

一致性非鎖定讀和多版本并發(fā)控制

一致性非鎖定讀(consistent nonlocking read)是指InnoDB通過行多版本控制(Multi Version Concurrency Control, MVCC)的方法來讀取當前執(zhí)行時間數(shù)據(jù)庫中行的數(shù)據(jù)。

即如果讀取的行正在執(zhí)行變更操作,這時讀取不會等待行鎖的釋放,而是會讀取行的一個快照數(shù)據(jù)??煺帐侵冈撔械囊粋€歷史數(shù)據(jù),通過undo操作來完成。這種方式極大提高了數(shù)據(jù)庫的并發(fā)性,這也是InnoDB的默認設(shè)置。

快照是當前行的一個歷史版本,但可能存在多個版本,行數(shù)據(jù)存在多個快照數(shù)據(jù),這種技術(shù)成為行多版本技術(shù),由此帶來的并發(fā)控制,稱為多版本并發(fā)控制(MVCC)。InnoDB在READ COMMITED 和 REPEATABLE READ隔離級別時,會使用非鎖定的一致性讀,但是在這兩種隔離級別使用的快找數(shù)據(jù)定義卻不同:

 ● READ COMMITED: 總是讀取最新一份快照

 ● REPEATABLE READ: 總是讀取事務(wù)開始時的行數(shù)據(jù)版本

我們執(zhí)行一個示例:

一致性非鎖定讀
時間會話A會話B
1BEGIN
2select * from z where a = 3;
3
BEGIN
4
update z set b=2 where a=3;
5select * from z where a = 3;
6
COMMIT;
7select * from z where a = 3;
8COMMIT;

在這個例子中我們可以清晰的看到0、1、2三種隔離級別的區(qū)別:

#在事務(wù)開始前我們可以分別調(diào)整為0、1、2三種隔離級別,來查看不同的輸出
mysql> set session transaction isolation level READ UNCOMMITTED;
Query OK, 0 rows affected (0.00 sec)

mysql> select @@tx_isolation;
+------------------+
| @@tx_isolation   |
+------------------+
| READ-UNCOMMITTED |
+------------------+
1 row in set (0.00 sec)

# A會話:T1事務(wù)
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from z where a = 3;
+---+------+
| a | b    |
+---+------+
| 3 |    1 |
+---+------+
1 row in set (0.00 sec)

# B會話:T2事務(wù)
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update z set b=2 where a=3;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

# A會話:T1事務(wù),如果此時隔離級別是READ-UNCOMMITTED,因為此刻事務(wù)2可能會回滾,所以出現(xiàn)了臟讀
mysql> select * from z where a=3;
+---+------+
| a | b    |
+---+------+
| 3 |    2 |
+---+------+
1 row in set (0.00 sec)

# A會話:T1事務(wù),如果此時隔離級別是大于READ-UNCOMMITTED的更高級別
mysql> select * from z where a=3;
+---+------+
| a | b    |
+---+------+
| 3 |    1 |
+---+------+
1 row in set (0.00 sec)

# B會話:T2事務(wù)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)

# A會話:T1事務(wù),如果此時隔離級別是READ-COMMITTED,因為數(shù)據(jù)和事務(wù)開始時讀取的出現(xiàn)了不一致,因此稱為不可重復(fù)讀,能夠讀到其他事務(wù)的結(jié)果,違反了事務(wù)的隔離性
mysql> select * from z where a=3;
+---+------+
| a | b    |
+---+------+
| 3 |    2 |
+---+------+
1 row in set (0.00 sec)

# A會話:T1事務(wù),如果此時隔離級別是大于READ-COMMITTED的更高級別
mysql> select * from z where a=3;
+---+------+
| a | b    |
+---+------+
| 3 |    1 |
+---+------+
1 row in set (0.00 sec)

# A會話:T1事務(wù)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)

一致性鎖定讀和SERIALIZABLE隔離

在默認的REPEATABLE READ隔離級別時,InnoDB使用的是一致性非鎖定讀。但有時我們也需要顯示的指定使用一致性鎖定讀來保證讀取操作時對數(shù)據(jù)進行加鎖達到一致性。這要求數(shù)據(jù)庫支持鎖定讀加鎖語句:

 ● select ... for update: 讀取時對行記錄加X鎖

 ● select ... lock in share mode:讀取時對行記錄加一個S鎖

這兩種鎖必須在一個事務(wù)中,當事務(wù)提交后鎖也就釋放了,因此務(wù)必加上BEGIN, START TRANSACTION或者SET AUTOCOMMIT=0。

我們在前面隔離級別時也說過SERIALIZABLE隔離級別會對讀操作自動加上LOCK IN SHARE MODE指令來加上一個共享鎖,因此不再支持一致性的非鎖定讀。這也是隔離級別3的一大特性。

總結(jié)

由于鎖的概念非常重要,這里先講了鎖的概念、鎖的類型、鎖的信息查看、事務(wù)的隔離級別和區(qū)別,后面我們會繼續(xù)說鎖的算法、鎖的三種問題和幻讀、死鎖和鎖升級。

看完上述內(nèi)容,你們對MySQL中的鎖和事務(wù)隔離級別有進一步的了解嗎?如果還想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI