乐观锁的颗粒度_MySql数据库锁机制详解
概述
數據庫鎖定機制簡單的來說,就是數據庫為了保證數據的一致性與完整性,而使各種共享資源在被并發訪問時變得有序所設計的一種規則。對于任何一種數據庫來說都需要有相應的鎖機制,所以MySQL也不能例外。MySQL數據庫根據鎖鎖定數據的顆粒度可分為表級鎖、行級鎖和頁級鎖。
一、表級鎖
1.1 什么是表級鎖
表級鎖會直接鎖定整張表。表級鎖是MySQL各存儲引擎中最大顆粒度的鎖定機制。該鎖定機制最大的特點是實現邏輯簡單,帶來的系統負面影響最小。所以獲取鎖和釋放鎖的速度很快。由于表級鎖一次會將整個表鎖定,所以可以很好的避免死鎖問題。當然,鎖定顆粒度大所帶來負面影響就是出現爭用鎖定資源的概率也會最高,致使并發度大大降低。
1.2 表級鎖的鎖模式
MySQL的表級鎖有兩種模式:表共享讀鎖和表獨占寫鎖;表共享讀鎖,不會阻塞其他用戶對同一表的讀請求,但會阻塞對同一表的寫請求;表獨占寫鎖,會阻塞其他用戶對同一表的讀和寫操作;表共享讀鎖與表獨占寫鎖之間,以及表獨占寫鎖之間是串行的。當一個線程獲得對一個表的寫鎖后,只有持有鎖的線程可以對表進行更新操作。其他線程的讀、寫操作都會等待,直到鎖被釋放為止。
1.3 表鎖優化建議
雖然使用表級鎖定在鎖定實現的過程中比實現行級鎖定或者頁級鎖所帶來的附加成本都要小,鎖定本身所消耗的資源也最少。但是由于鎖定的顆粒度比較大,所以造成爭用鎖定資源的情況也會比其他的鎖級別都要多,從而在較大程度上會降低并發處理能力。所以,在優化表級鎖問題的時候,最關鍵的就是如何讓其提高并發度。由于鎖定級別是不可能改變的了,所以我們首先需要盡可能讓鎖定的時間變短,然后就是讓可能并發進行的操作盡可能的并發。
二、行級鎖
2.1 什么是行級鎖
行級鎖僅對指定的記錄加鎖。行級鎖最大的特點就是鎖定對象的顆粒度小,也是目前各大數據庫管理軟件所實現的鎖定顆粒度最小的。由于鎖定顆粒度很小,所以發生爭用鎖定資源的概率也最小,能盡可能大的提高數據庫的并發處理能力從而提高高并發應用系統的性能。雖然行級鎖能夠極大提高并發處理能力,但是由于鎖定資源的顆粒度很小,所以每次獲取鎖和釋放鎖需要做的事情也更多,帶來的消耗自然也就更大了。此外,行級鎖定也最容易發生死鎖。
2.2 行級鎖的鎖模式
MySQL行級鎖有共享鎖和排他鎖兩種。當一個事務需要給自己需要的某個資源加鎖的時候,如果遇到一個共享鎖正鎖定著自己需要的資源的時候,自己可以再加一個共享鎖,不過不能加排他鎖。但是,如果遇到自己需要鎖定的資源已經被一個排他鎖占有之后,則只能等待該鎖定釋放資源之后自己才能獲取鎖定資源并添加自己的鎖定。如果一個事務請求的鎖模式與當前的鎖兼容,InnoDB就將請求的鎖授予該事務;反之,如果兩者不兼容,該事務就要等待鎖釋放。
2.3 行鎖優化建議
InnoDB行鎖是通過給索引上的索引項加鎖來實現的,只有通過索引條件檢索數據,InnoDB才使用行級鎖,否則,InnoDB將使用表鎖。在實際應用中,要特別注意InnoDB行鎖的這一特性,不然的話,可能導致大量的鎖沖突,從而影響并發性能。下面通過一些實際例子來加以說明。
1、在不通過索引條件查詢的時候,InnoDB確實使用的是表鎖,而不是行鎖;
2、由于MySQL的行鎖是針對索引加的鎖,不是針對記錄加的鎖,所以雖然是訪問不同行的記錄,但是如果是使用相同的查詢條件,是會出現鎖沖突的;
3、當表有多個索引的時候,不同的事務可以使用不同的索引鎖定不同的行,另外,不論是使用主鍵索引、唯一索引或普通索引,InnoDB都會使用行鎖來對數據加鎖;
4、即便在條件中使用了索引字段,但是否使用索引來檢索數據是由MySQL通過判斷不同執行計劃的代價來決定的,如果MySQL認為全表掃描效率更高,比如對一些很小的表,它就不會使用索引,這種情況下InnoDB將使用表鎖,而不是行鎖;
2.4 間隙鎖
當我們用范圍條件而不是相等條件檢索數據并請求共享鎖或排他鎖時,InnoDB會給符合條件的已有數據記錄的索引項加鎖;對于鍵值在條件范圍內但并不存在的記錄,叫做“間隙(GAP)”,InnoDB也會對這個“間隙”加鎖,這種鎖機制就是間隙鎖。
假如userInfo表中只有50條記錄,其userId的值分別是1,2,3,....,49,50;
下面的SQL:
mysql> select * from emp where userId > 49 for update;
是一個范圍條件的檢索,InnoDB不僅會對符合條件的userId值為50的記錄加鎖,也會對userId大于50(這些記錄并不存在)的“間隙”加鎖。
InnoDB使用間隙鎖的目的是防止幻讀,以滿足相關隔離級別的要求。對于上面的例子,如果不使用間隙鎖,若其他事務插入了userId大于50的任何記錄,那么本事務如果再次執行上述語句,就會發生幻讀;因為間隙鎖鎖定的是一個范圍,而不是具體的索引鍵所以在使用范圍條件檢索并鎖定記錄時,間隙鎖會將不存在的鍵值也會被無辜的鎖定,而造成在鎖定的時候無法插入鎖定鍵值范圍內的任何數據。因此,在實際應用開發中,尤其是并發插入比較多的應用,我們要盡量優化業務邏輯,盡量使用相等條件來訪問更新數據,避免使用范圍條件。還要特別說明的是,InnoDB除了通過范圍條件加鎖時使用間隙鎖外,如果使用相等條件請求給一個不存在的記錄加鎖,InnoDB也會使用間隙鎖。
2.5 行鎖優化建議
1、盡量讓所有的查詢條件都通過索引來完成,從而避免InnoDB因為無法通過索引鍵加鎖而升級為表級鎖定;
2、合理設計索引,讓InnoDB在索引鍵上面加鎖的時候盡可能準確,盡可能的縮小鎖定范圍,避免造成不必要的鎖定而影響其它SQL的執行;
3、減少基于范圍的數據檢索過濾條件,避免因為間隙鎖帶來的負面影響而鎖定了不該鎖定的記錄;
4、盡量控制事務的大小,減少鎖定的資源量和鎖定時間長度;
5、在業務環境允許的情況下,可使用較低級別的事務隔離,以減少MySQL因為實現事務隔離級別所帶來的附加成本;
6、類似業務模塊中,盡量按照相同的訪問順序來訪問,防止產生死鎖;
7、在同一個事務中,盡量做到一次鎖定所需要的所有資源,減少死鎖產生概率;
8、對于非常容易產生死鎖的業務部分,可以嘗試使用升級鎖定顆粒度,通過表級鎖定來減少死鎖產生的概率;
三、頁級鎖
頁級鎖是MySQL中比較獨特的一種鎖定級別,在其他數據庫管理軟件中并不是太常見。頁級鎖定的特點是鎖定顆粒度介于行級鎖定與表級鎖之間,所以獲取鎖定所需要的資源開銷,以及所能提供的并發處理能力也同樣是介于上面二者之間。另外,頁級鎖定和行級鎖定一樣,會發生死鎖。
在數據庫實現資源鎖定的過程中,隨著鎖定資源顆粒度的減小,鎖定相同數據量的數據所需要消耗的內存數量是越來越多的,實現算法也會越來越復雜。不過,隨著鎖定資源顆粒度的減小,應用程序的訪問請求遇到鎖等待的可能性也會隨之降低,系統整體并發度也隨之提升。
總的來說,MySQL這3種鎖的特性可大致歸納如下:
表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖沖突的概率最高,并發度最低;
行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的概率最低,并發度也最高;
頁面鎖:開銷和加鎖時間界于表鎖和行鎖之間;會出現死鎖;鎖定粒度界于表鎖和行鎖之間,并發度一般。
四、行級鎖和表級鎖能共存嗎?
行級鎖與表級鎖是可以共存的。InnoDB為了讓表鎖和行鎖共存而引入了意向鎖。
舉個例子(此時假設行鎖和表鎖能共存): 事務A鎖住表中的一行(寫鎖)。事務B鎖住整個表(寫鎖)。
但你就會發現一個很明顯的問題,事務A既然鎖住了某一行,其他事務就不可能修改這一行。這與"事務B鎖住整個表就能修改表中的任意一行"形成了沖突。所以,沒有意向鎖的時候,行鎖與表鎖共存就會存在問題!
那么意向鎖是如何讓表鎖和行鎖共存的?
有了意向鎖之后,前面例子中的事務A在申請行鎖(寫鎖)之前,數據庫會自動先給事務A申請表的意向排他鎖。當事務B去申請表的寫鎖時就會失敗,因為表上有意向排他鎖之后事務B申請表的寫鎖時會被阻塞。由此我們可得出意向鎖是表鎖。
(更多文章可關注微信公眾號:IT雞窩)
參考文章:https://blog.csdn.net/zcl_love_wx/article/details/82015281https://www.cnblogs.com/sessionbest/articles/8689071.html總結
以上是生活随笔為你收集整理的乐观锁的颗粒度_MySql数据库锁机制详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我的世界移动版天气系统介绍 下雪指令是什
- 下一篇: mysql8 优化_MySQL 8.0