首頁 資料庫 mysql教程 MySQL之鎖和事務隔離等級(介紹)

MySQL之鎖和事務隔離等級(介紹)

Nov 23, 2019 pm 04:58 PM
innodb mvcc mysql 事務

如今的互聯網,開發一個大型的多人APP,你一定離不開資料庫。而如何確保所有人能夠高並發的進行讀寫一直是一個高難度的架構問題,先刨去高並發,保證一致性讀寫這個問題最常用的手段是事務,而實現一個事務的關鍵點在於鎖機制。

MySQL之鎖和事務隔離等級(介紹)

今天我們就來介紹下InnoDB儲存引擎如何在高並發下實作鎖定機制來滿足一致性讀寫的原理與實作。

鎖定

資料庫的鎖定機制是區別於檔案系統的關鍵特性。用於管理對共享資源的並發存取。 InnoDB會在許多地方使用鎖定機制,例如操作緩衝池中的資料表、LRU頁列表、資料行,為了確保一致性和完整性,需要有鎖定的機制。

對於不同資料庫,鎖定機制的設計和實作完全不同:

 ● MyISAM引擎: 表鎖定設計,並發讀取沒有問題,並發寫效能差。

 ● Microsoft SQL Server: 支援樂觀並發和悲觀並發,樂觀並發下支援行級鎖,維持鎖的開銷大,在行鎖數量超過閾值後會升級為表鎖。

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

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

兩類鎖定:lock和latch

#資料庫中lock和latch都可以稱為鎖,但有很大的差別。

latch一般稱為閂鎖,用於保證並發執行緒操作臨界資源的正確性,作用物件是記憶體資料結構,要求鎖定時間非常短,不會偵測死鎖。在InnoDB引擎中又分為mutex(互斥量)和rwlock(讀寫鎖定)。

lock是用來鎖定資料庫中的對象,如表、頁、行,作用對像是事務,在commit/rollback後釋放,會偵測死鎖。分為行鎖、表鎖、意向鎖。

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

四種鎖定類型

InnoDB支援四個鎖定:

 ● 共享鎖定(S Lock):允許事務讀一行資料

 ● 排他鎖(X Lock):允許交易刪除或更新一行資料

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

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

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

而當事務T3想要取得行r的排他鎖進行修改資料時,就需要等待T1/T2釋放行共享鎖定,此時稱為鎖不相容。

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

鎖定的相容性:

不相容##X#不相容不相容不相容

#IS IX S X
IS 相容 #相容 相容 不相容
IX 相容 ##不相容 不相容
#S 相容
##不相容

不相容

存儲事務和鎖定資訊的三張表

我們可以透過

show engine innodb status

指令在交易部分查看目前鎖定請求的資訊。 從InnoDB1.0開始,在INFORMATION_SCHEMA架構下新增了INNODB_TRX(transaction事務表)、INNODB_LOCKS(鎖定表)、INNODB_LOCK_WAITS(鎖定等待表),透過這三張表,可以讓我們即時監控目前事務並分析可能存在的表問題。 ##trx_idtrx_statetrx_startedtrx_requested_lock_idtrx_wait_started#trx_weighttrx_mysql_thread_idtrx_query
三個表格的定義分別為:
INNODB_TRX
InnoDB儲存引擎內部唯一的交易ID
目前交易的狀態
事務的開始時間
等待交易的鎖定IDC,當狀態不為LOCK WAIT時為NULL
交易等待開始的時間
交易的權重,反映一個交易修改和鎖定的行數。當需要回滾時,選擇該值最小的交易進行回滾
MySQL的執行緒ID,show processlist顯示的結果
交易運行的SQL語句##############鎖定ID#lock_trx_id交易IDlock_mode鎖定的模式lock_type鎖定的類型,表格鎖定或行鎖定lock_table#要加鎖的表格lock_index鎖定的索引lock_space已鎖定物件的space idlock_page交易鎖定頁的數量,表鎖定時為NULLlock_rec#交易鎖定行的數量,表鎖定時為NULLlock_data交易鎖定記錄的主鍵值,表鎖定時為NULL
INNODB_LOCKS
#lock_id
requesting_trx_id申請鎖定資源的交易IDrequesting_lock_idblocking_trx_idblocking_lock_id透過
INNODB_LOCK_WAITS
##申請的鎖的ID
阻塞的事務ID
#阻塞的鎖定的ID
INNODB_TRX

我們可以看到所有的事務,以及事務是否被阻塞,阻塞的鎖定ID是什麼。 之後,透過INNODB_LOCKS
查看所有的鎖定資訊。 之後,透過INNODB_LOCK_WAITS
可以查看到鎖的等待資訊以及阻塞關係。 透過這三種表格能夠較為清晰的查看事務和鎖的情況,也可以聯合查詢,在下面的一些場景下我們會來展示這三個表的內容。

隔離等級首先我們來說下資料庫的四個交易隔離等級:

 ● READ UNCOMMITTED(0 ): 瀏覽存取級別,存在髒讀、不可重複讀取、幻讀

 ● READ COMMITTED(1): 遊標穩定級別,存在不可重複度、幻讀

# ● REPEATABLE READ( 2): 存在幻讀

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

這四種事務隔離級別是指定的SQL標準, InnoDB預設的隔離等級是REAPEATABLE READ,但當與其他資料庫不同的時,它同時使用了Next-Key-Lock鎖定的演算法,能夠避免幻讀的產生,因此能夠完全滿足事務的隔離性要求,即達到SERIALIZABLE隔離等級。

隔離等級越低,交易要求的鎖定越少或持鎖時間越短,因此大部分資料庫的預設隔離等級為READ COMMITED。但有相關的分析也指出,隔離等級的效能開銷幾乎一樣,因此使用者無須透過調整隔離等級來提高效能。

查看和修改事務隔離級別的命令:

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)
登入後複製

範例中修改了本次會話的事務隔離級別,如果需要修改全域參數,可以替換session為global。如果想要永久修改,需要修改設定檔:

[mysqld]
transaction-isolation = READ-COMMITED
登入後複製

在SERIALIZABLE的交易隔離級別,InnoDB會對每個SELECT語句後自動加上LOCK IN SHARE MODE,來對讀取操作加上一個共享鎖,因此不再支援一致性的非鎖定讀取。

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

一致性非鎖定讀和多版本並發控制#一致性非鎖定讀(consistent nonlocking read)是指InnoDB通過行多版本控制(Multi Version Concurrency Control, MVCC)的方法來讀取目前執行時間資料庫中行的資料。

也就是如果讀取的行正在執行變更操作,這時讀取不會等待行鎖的釋放,而是會讀取行的一個快照資料。快照是指該行的一個歷史數據,透過undo操作來完成。這種方式極大地提高了資料庫的並發性,這也是InnoDB的預設值。

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

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

 ● REPEATABLE READ: 總是讀取事務開始時的行資料版本

我們執行一個範例:

一致性非鎖定讀取1#234#56##COMMIT;7#8
會話A 會話B
BEGIN
select * from z where a = 3;

#BEGIN

update z set b=2 where a=3;
select * from z where a = 3 ;

COMMIT;

select * from z where a = 3;
#COMMIT;## ###################

在这个例子中我们可以清晰的看到0、1、2三种隔离级别的区别:

#在事务开始前我们可以分别调整为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事务
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事务
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事务,如果此时隔离级别是READ-UNCOMMITTED,因为此刻事务2可能会回滚,所以出现了脏读
mysql> select * from z where a=3;
+---+------+
| a | b    |
+---+------+
| 3 |    2 |
+---+------+
1 row in set (0.00 sec)

# A会话:T1事务,如果此时隔离级别是大于READ-UNCOMMITTED的更高级别
mysql> select * from z where a=3;
+---+------+
| a | b    |
+---+------+
| 3 |    1 |
+---+------+
1 row in set (0.00 sec)

# B会话:T2事务
mysql> commit;
Query OK, 0 rows affected (0.00 sec)

# A会话:T1事务,如果此时隔离级别是READ-COMMITTED,因为数据和事务开始时读取的出现了不一致,因此称为不可重复读,能够读到其他事务的结果,违反了事务的隔离性
mysql> select * from z where a=3;
+---+------+
| a | b    |
+---+------+
| 3 |    2 |
+---+------+
1 row in set (0.00 sec)

# A会话:T1事务,如果此时隔离级别是大于READ-COMMITTED的更高级别
mysql> select * from z where a=3;
+---+------+
| a | b    |
+---+------+
| 3 |    1 |
+---+------+
1 row in set (0.00 sec)

# A会话:T1事务
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
登入後複製

一致性锁定读和SERIALIZABLE隔离

在默认的REPEATABLE READ隔离级别时,InnoDB使用的是一致性非锁定读。但有时我们也需要显示的指定使用一致性锁定读来保证读取操作时对数据进行加锁达到一致性。这要求数据库支持锁定读加锁语句:

 ● select ... for update: 读取时对行记录加X锁

 ● select ... lock in share mode:读取时对行记录加一个S锁

这两种锁必须在一个事务中,当事务提交后锁也就释放了,因此务必加上BEGIN, START TRANSACTION或者SET AUTOCOMMIT=0。

我们在前面隔离级别时也说过SERIALIZABLE隔离级别会对读操作自动加上LOCK IN SHARE MODE指令来加上一个共享锁,因此不再支持一致性的非锁定读。这也是隔离级别3的一大特性。

总结

由于锁的概念非常重要,这里先讲了锁的概念、锁的类型、锁的信息查看、事务的隔离级别和区别,后面我们会继续说锁的算法、锁的三种问题和幻读、死锁和锁升级。

推荐学习:MySQL教程

以上是MySQL之鎖和事務隔離等級(介紹)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它們
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

mysql:簡單的概念,用於輕鬆學習 mysql:簡單的概念,用於輕鬆學習 Apr 10, 2025 am 09:29 AM

MySQL是一個開源的關係型數據庫管理系統。 1)創建數據庫和表:使用CREATEDATABASE和CREATETABLE命令。 2)基本操作:INSERT、UPDATE、DELETE和SELECT。 3)高級操作:JOIN、子查詢和事務處理。 4)調試技巧:檢查語法、數據類型和權限。 5)優化建議:使用索引、避免SELECT*和使用事務。

phpmyadmin怎麼打開 phpmyadmin怎麼打開 Apr 10, 2025 pm 10:51 PM

可以通過以下步驟打開 phpMyAdmin:1. 登錄網站控制面板;2. 找到並點擊 phpMyAdmin 圖標;3. 輸入 MySQL 憑據;4. 點擊 "登錄"。

MySQL:世界上最受歡迎的數據庫的簡介 MySQL:世界上最受歡迎的數據庫的簡介 Apr 12, 2025 am 12:18 AM

MySQL是一種開源的關係型數據庫管理系統,主要用於快速、可靠地存儲和檢索數據。其工作原理包括客戶端請求、查詢解析、執行查詢和返回結果。使用示例包括創建表、插入和查詢數據,以及高級功能如JOIN操作。常見錯誤涉及SQL語法、數據類型和權限問題,優化建議包括使用索引、優化查詢和分錶分區。

為什麼要使用mysql?利益和優勢 為什麼要使用mysql?利益和優勢 Apr 12, 2025 am 12:17 AM

選擇MySQL的原因是其性能、可靠性、易用性和社區支持。 1.MySQL提供高效的數據存儲和檢索功能,支持多種數據類型和高級查詢操作。 2.採用客戶端-服務器架構和多種存儲引擎,支持事務和查詢優化。 3.易於使用,支持多種操作系統和編程語言。 4.擁有強大的社區支持,提供豐富的資源和解決方案。

redis怎麼使用單線程 redis怎麼使用單線程 Apr 10, 2025 pm 07:12 PM

Redis 使用單線程架構,以提供高性能、簡單性和一致性。它利用 I/O 多路復用、事件循環、非阻塞 I/O 和共享內存來提高並發性,但同時存在並發性受限、單點故障和不適合寫密集型工作負載的局限性。

MySQL和SQL:開發人員的基本技能 MySQL和SQL:開發人員的基本技能 Apr 10, 2025 am 09:30 AM

MySQL和SQL是開發者必備技能。 1.MySQL是開源的關係型數據庫管理系統,SQL是用於管理和操作數據庫的標準語言。 2.MySQL通過高效的數據存儲和檢索功能支持多種存儲引擎,SQL通過簡單語句完成複雜數據操作。 3.使用示例包括基本查詢和高級查詢,如按條件過濾和排序。 4.常見錯誤包括語法錯誤和性能問題,可通過檢查SQL語句和使用EXPLAIN命令優化。 5.性能優化技巧包括使用索引、避免全表掃描、優化JOIN操作和提升代碼可讀性。

SQL刪除行後如何恢復數據 SQL刪除行後如何恢復數據 Apr 09, 2025 pm 12:21 PM

直接從數據庫中恢復被刪除的行通常是不可能的,除非有備份或事務回滾機制。關鍵點:事務回滾:在事務未提交前執行ROLLBACK可恢復數據。備份:定期備份數據庫可用於快速恢復數據。數據庫快照:可創建數據庫只讀副本,在數據誤刪後恢復數據。慎用DELETE語句:仔細檢查條件,避免誤刪數據。使用WHERE子句:明確指定要刪除的數據。使用測試環境:在執行DELETE操作前進行測試。

MySQL的位置:數據庫和編程 MySQL的位置:數據庫和編程 Apr 13, 2025 am 12:18 AM

MySQL在數據庫和編程中的地位非常重要,它是一個開源的關係型數據庫管理系統,廣泛應用於各種應用場景。 1)MySQL提供高效的數據存儲、組織和檢索功能,支持Web、移動和企業級系統。 2)它使用客戶端-服務器架構,支持多種存儲引擎和索引優化。 3)基本用法包括創建表和插入數據,高級用法涉及多表JOIN和復雜查詢。 4)常見問題如SQL語法錯誤和性能問題可以通過EXPLAIN命令和慢查詢日誌調試。 5)性能優化方法包括合理使用索引、優化查詢和使用緩存,最佳實踐包括使用事務和PreparedStatemen

See all articles