如今的互聯網,開發一個大型的多人APP,你一定離不開資料庫。而如何確保所有人能夠高並發的進行讀寫一直是一個高難度的架構問題,先刨去高並發,保證一致性讀寫這個問題最常用的手段是事務,而實現一個事務的關鍵點在於鎖機制。
今天我們就來介紹下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支援表鎖,因此意向鎖不會阻塞除全表掃描外的任何請求。
鎖定的相容性:
#IS | IX | S | X | |
IS | 相容 | #相容 | 相容 | 不相容 |
IX | 相容 | ##不相容 | 不相容 | |
#S | 相容 | |||
##不相容 | ##X | #不相容 | 不相容 |
不相容
存儲事務和鎖定資訊的三張表
show engine innodb status
指令在交易部分查看目前鎖定請求的資訊。三個表格的定義分別為:
| |
---|---|
INNODB_TRX | |
InnoDB儲存引擎內部唯一的交易ID | |
目前交易的狀態 | |
事務的開始時間 | |
等待交易的鎖定IDC,當狀態不為LOCK WAIT時為NULL | |
交易等待開始的時間 | |
交易的權重,反映一個交易修改和鎖定的行數。當需要回滾時,選擇該值最小的交易進行回滾 | |
MySQL的執行緒ID,show processlist顯示的結果 |
INNODB_LOCKS | |
---|---|
#lock_id | ##鎖定ID|
交易ID | |
鎖定的模式 | |
鎖定的類型,表格鎖定或行鎖定 | |
#要加鎖的表格 | |
鎖定的索引 | |
已鎖定物件的space id | |
交易鎖定頁的數量,表鎖定時為NULL | |
#交易鎖定行的數量,表鎖定時為NULL | |
交易鎖定記錄的主鍵值,表鎖定時為NULL |
INNODB_LOCK_WAITS
| |
---|---|
申請鎖定資源的交易ID | |
##申請的鎖的ID | |
阻塞的事務ID | |
#阻塞的鎖定的ID |
我們可以看到所有的事務,以及事務是否被阻塞,阻塞的鎖定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: 總是讀取事務開始時的行資料版本
我們執行一個範例:
|
||
---|---|---|
會話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; |
||
##COMMIT; | ||
select * from z where a = 3; |
在这个例子中我们可以清晰的看到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中文網其他相關文章!

InnoDB使用redologs和undologs確保數據一致性和可靠性。 1.redologs記錄數據頁修改,確保崩潰恢復和事務持久性。 2.undologs記錄數據原始值,支持事務回滾和MVCC。

EXPLAIN命令的關鍵指標包括type、key、rows和Extra。 1)type反映查詢的訪問類型,值越高效率越高,如const優於ALL。 2)key顯示使用的索引,NULL表示無索引。 3)rows預估掃描行數,影響查詢性能。 4)Extra提供額外信息,如Usingfilesort提示需要優化。

Usingtemporary在MySQL查詢中表示需要創建臨時表,常見於使用DISTINCT、GROUPBY或非索引列的ORDERBY。可以通過優化索引和重寫查詢避免其出現,提升查詢性能。具體來說,Usingtemporary出現在EXPLAIN輸出中時,意味著MySQL需要創建臨時表來處理查詢。這通常發生在以下情況:1)使用DISTINCT或GROUPBY時進行去重或分組;2)ORDERBY包含非索引列時進行排序;3)使用複雜的子查詢或聯接操作。優化方法包括:1)為ORDERBY和GROUPB

MySQL/InnoDB支持四種事務隔離級別:ReadUncommitted、ReadCommitted、RepeatableRead和Serializable。 1.ReadUncommitted允許讀取未提交數據,可能導致臟讀。 2.ReadCommitted避免臟讀,但可能發生不可重複讀。 3.RepeatableRead是默認級別,避免臟讀和不可重複讀,但可能發生幻讀。 4.Serializable避免所有並發問題,但降低並發性。選擇合適的隔離級別需平衡數據一致性和性能需求。

MySQL適合Web應用和內容管理系統,因其開源、高性能和易用性而受歡迎。 1)與PostgreSQL相比,MySQL在簡單查詢和高並發讀操作上表現更好。 2)相較Oracle,MySQL因開源和低成本更受中小企業青睞。 3)對比MicrosoftSQLServer,MySQL更適合跨平台應用。 4)與MongoDB不同,MySQL更適用於結構化數據和事務處理。

MySQL索引基数对查询性能有显著影响:1.高基数索引能更有效地缩小数据范围,提高查询效率;2.低基数索引可能导致全表扫描,降低查询性能;3.在联合索引中,应将高基数列放在前面以优化查询。

MySQL學習路徑包括基礎知識、核心概念、使用示例和優化技巧。 1)了解表、行、列、SQL查詢等基礎概念。 2)學習MySQL的定義、工作原理和優勢。 3)掌握基本CRUD操作和高級用法,如索引和存儲過程。 4)熟悉常見錯誤調試和性能優化建議,如合理使用索引和優化查詢。通過這些步驟,你將全面掌握MySQL的使用和優化。

MySQL在現實世界的應用包括基礎數據庫設計和復雜查詢優化。 1)基本用法:用於存儲和管理用戶數據,如插入、查詢、更新和刪除用戶信息。 2)高級用法:處理複雜業務邏輯,如電子商務平台的訂單和庫存管理。 3)性能優化:通過合理使用索引、分區表和查詢緩存來提升性能。


熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

SublimeText3 Linux新版
SublimeText3 Linux最新版

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中