1.2. 併發控制
任何時候只要有多個查詢語句想要改變同一條資料時併發控制的問題就出現了。根據這一章的描述,mysql在需要在兩個層面來解決這個問題:伺服器層面和儲存引擎層面。併發控制是乙個很大的課題,同時也有一大批關於併發控制的專著,但是本書的著眼點並不在於併發控制的理論或者mysql的內部實現。因此我們只打算給讀者乙個關於如何處理併發讀操作和併發寫操作的概述,因此讀者可以在本章的其餘部分看到這部分內容。
我們用unix系統中的電子郵件箱來作為例子說明這個問題。經典的mbox檔案格式很簡單。mbox郵件箱中的所有郵件被乙個乙個連線在一起。這使得郵件訊息很容易閱讀和解析。它也使得郵件接收變得很簡單,只需要將新郵件附加到mbox檔案尾就可以了。
但是當兩個不同的程序同時接收郵件到同乙個郵箱時會發生什麼事情呢?很顯然那個郵件箱會崩潰,因為它裡面會出現兩個交織在一起的郵件。乙個好的郵件系統會使用鎖來阻止這種崩潰。當乙個客戶在郵件箱被鎖定的情況下往郵件箱裡寫入第二封郵件的時候,它必須一直等待直到它拿到那個鎖。
這個方案在現實世界中執行地很好,但是它卻不能提供併發性。這種方式在乙個大容量郵箱的情況下會很有問題,因為在指定時間裡只有乙個程序可以改變郵箱的內容。
1.2.1. 讀寫鎖
從郵箱中讀郵件不是問題。多個客戶端同時讀乙個郵箱一點問題都沒有,因為他們不會做出任何改動,因此所有的事情都不會出錯。但是當有人試圖刪除第25個郵件而另外的程式正在讀這個郵件時會發生什麼事呢?這就不一定了,讀者可能得到乙個崩潰和或者不一致的郵箱檢視。因此從安全上來說,即使是從郵箱中讀郵件也需要額外注意。
如果你把郵箱看成資料庫中的表,而把乙個個郵件看成資料庫表中的資料行,那麼前面談論到的郵箱中存在的問題在資料庫中同樣存在。從各方面來說,郵箱可以看成乙個簡單的資料庫。修改資料庫表中的資料行與刪除或者更新郵箱中的郵件十分相似。
解決這個經典的併發控制問題的方法十分簡單。處理併發讀寫訪問的系統實際上實現了乙個由兩種不同型別的鎖組成的鎖定系統。這些鎖被稱為「共享鎖」和「互斥鎖」或者叫「讀鎖」和「寫鎖」。
如果不用關心實際的鎖定技術,那麼這些概念可以描述如下:乙個資源上的讀鎖是共享的,或者互助非阻塞的,多個客戶端可以同時讀取同乙個資源而不互相干擾;另一方面,寫鎖是互斥的,也即它同時阻止讀鎖和其他寫鎖,因為唯一安全的策略是保證在指定時間裡同時只有乙個客戶端在寫入,並且在寫入時沒有任何乙個客戶端在讀取資料。
在資料庫的世界裡,鎖定時時發生:mysql必須阻止乙個客戶在修改資料時另乙個客戶讀取這段資料。它多數情況下會在內部透明地執行這個鎖管理。
1.2.2. 鎖的粒度
改善乙個共享資源的併發性的乙個途徑是使得你鎖定的東西更加具有可選擇性。不是鎖定整個資源,而是只需要鎖定那些你需要改變資料的部分。乙個比較好的做法是只鎖定你想要改變的資料部分。任何時候一次只鎖定盡可能少的資料,只要這些資料之間沒有衝突,那麼就可以使得指定資源同時發生改變。
問題是鎖會消耗資源。每個鎖操作,包括獲取乙個鎖,檢查乙個鎖是否空閒,釋放乙個鎖等,它們都會產生額外的開銷。如果系統把大量的時間花在管理鎖而不是在資料的訪問上,那麼這個資料庫的效能將是無法忍受的。
鎖策略是對於鎖開銷和資料安全之間的一種妥協,而這種妥協會影響效率。大多數商業資料庫不會讓你有過多的選擇:你會得到資料庫表上的乙個所謂行級鎖,以及許多利用很多鎖來提高效率的方法,而這些方法經常會很複雜。
另一方面,mysql卻為使用者提供了很多選擇。不同的儲存引擎各自實現了不同的鎖策略以及鎖粒度。鎖管理是儲存引擎管理中乙個非常重要的決策;對於特定的應用來說,將粒度固定在某乙個特定級別可以提高效率,但是這可能會使得那個引擎對於其他應用來說不太適合。但是由於mysql的儲存引擎架構,mysql並不需要提供乙個通用的解決方案。接下來讓我們來看兩個最重要的鎖策略。
1.2.2.1. 表鎖
mysql中可以使用的最基本的鎖策略,同時也是開銷最小的鎖策略,是表鎖定。表鎖類似於之前描述過的郵箱鎖:它將會鎖定整張表。當乙個客戶想要往表中寫資料時(如insert, update, delete等),它就需要乙個寫鎖。它將阻止其他所有的讀寫操作。當沒有人寫入時,讀者可以獲取讀鎖,這個讀鎖不與其他的讀鎖相衝突。
表鎖定在一些特定情況下為了效率會有所不同。比如read local表鎖定允許一些型別的併發寫操作。另外寫鎖比讀鎖的優先順序要高,因此乙個寫鎖的請求將會被提前到鎖佇列的開頭,即使有讀者已經在佇列開頭了(寫鎖可以跨越讀鎖到鎖佇列開頭,但是讀鎖不能跨越寫鎖)。
儘管儲存引擎可以管理它們各自的鎖,mysql本身也用了很多高效的表級別的鎖以應對各自情況。比如伺服器為aleter table這種型別的語句使用了表級別的鎖,而不管是什麼儲存引擎。
1.2.2.2. 行鎖
可以提供最大併發性的鎖型別是行鎖(同時也是資源開銷最大的乙個)。innodb以及falcon儲存引擎以及其他一些引擎都提供了對行級別的鎖的支援。行鎖是在儲存引擎而不是伺服器上來實現的(如果你不知道mysql的整個架構的話,可以去參考mysql的邏輯架構圖)。伺服器對於在儲存引擎中實現的鎖是一無所知的,在本章的後續部分以及整本書中,你可以看到,儲存引擎一般都以自己的方式來實現鎖機制。
mysql 併發控制 mysql併發控制
mysql併發控制 當有多個查詢需要同時修改同乙個資料,就會產生併發控制的問題。mysql可以在兩個層面進行併發控制 伺服器層和儲存引擎層。mysql通過加鎖實現併發控制 鎖有兩類 讀鎖 共享鎖,即乙個讀鎖不會阻塞其它讀鎖,多個使用者可同時讀取同乙個資源,而不互相干擾。寫鎖 排他鎖,即乙個寫鎖會阻塞...
事務併發 併發控制(加鎖)
事務處理中的併發控制 1.併發操作 資料庫是乙個共享資源,允許多個使用者程式並行地訪問資料庫,所以當多個使用者併發地訪問同一資料,就可能出現資料的不一致性。例如 假設有兩個事務 t1 和 t2 它們都需要讀出並修改資料 a 其執 況如下所示 執行順序 1 2 3 4 5 6 事務t1 讀aa a 1...
高效能MySQL(第3版)筆記 1 2 併發控制
在處理併發讀或者寫時,可以通過實現乙個由兩種型別的鎖組成鎖系統來解決問題 共享鎖 shared lock 也叫讀鎖 read lock 排他鎖 exclusive lock 也叫寫鎖 write lock 讀鎖 共享,互不阻塞,多個客戶在同一時刻可以同時讀取同乙個資源而互不干擾 寫鎖 排他,會阻塞其...