前段時間阿粉在公司開發的時候,不慎導致了數據庫產生了鎖表的操作,因為阿粉之前從來沒有遇到過,之前只是了解過一點,所以導致了鎖表,于是阿粉為了解決問題,研究了一下這一部分的內容,于是決定把這一塊的知識分享給大家。
數據庫鎖定機制
話說如果你只是單純的說 "鎖表",總是讓人感覺有點 Low ,而我們就直接換個比較高大上一點的名詞,鎖定機制!
為了保證數據的完整,也就是他的一致性和有效性,所以才會讓數據庫出現了鎖定機制,相對其他數據庫而言,MySQL的鎖機制比較簡單,其最顯著的特點是不同的存儲引擎支持不同的鎖機制。
- MyISAM和MEMORY存儲引擎采用的是表級鎖(table-level locking)
- BDB存儲引擎采用的是頁面鎖(page-level locking),也支持表級鎖
- InnoDB存儲引擎既支持行級鎖(row-level locking),也支持表級鎖
我們先來瞅瞅看一下這些鎖都是個什么鬼東西!
行級鎖(row-level locking)
- 鎖的對象顆粒度很小
- 各大數據庫中鎖粒度最小的
- 鎖定資源占用概率最小
雖然說行級鎖的優點是很明顯,但是相對的弊端也因為他的優點出現了,
- 因為鎖定的粒度比較小,所以每次獲取鎖和釋放鎖需要做更多的內容,帶來的消耗必然也就更大了,
- 行級鎖也是最容易發生死鎖的。
- 并發度也最高
表級鎖(table-level locking)
- 和行鎖相反,粒度是最大的
- 邏輯簡單,對系統的負面影響比較小
- 獲取鎖和釋放鎖速度快
- 并發度最低。
弊端也有,因為粒度比較大,鎖定資源占用概率也會很大,
頁級鎖(page-level locking)
- 比較特殊,介于行鎖和表鎖之間,所以他的能力都是介于兩者之間的,就是
粒度比較 表級鎖 > 頁鎖 > 行鎖
而他的并發度也就是一般般了。但是他會出現死鎖,這三個當中,看來也就只有表鎖不會出現死鎖了。
我們在這里已經算是對鎖機制大致有了個了解,我們再細致的看一下
表鎖
表鎖實際上分為2種類型,
- 讀鎖定
- 寫鎖定
而這兩種鎖定,又是通過其內部的隊列來進行維護的,
- 當前讀鎖隊列 (Current read-lock queue)
- 掛起的讀鎖隊列(Pending read-lock queue)
- 掛起寫鎖隊列(Pending write-lock queue)
- 當前寫鎖隊列(Current write-lock queue)
什么意思呢?
當前讀鎖的隊列,實際上就是包含了當前所有的持有讀鎖的線程,這里面的內容就是按照獲取鎖的時間進行有序的排放,
而掛起的讀鎖隊列中存放的則是等待獲取所得線程。
那寫鎖大家肯定也知道是什么意思了,就像是個4*100接力一樣。拿著“棒子”的,就是當前讀/寫鎖隊列,等著接 “棒子” 的就是 掛起的讀/寫鎖隊列。
行鎖
MySQL的 InnoDB 存儲引擎支持行級鎖,InnoDB 的行鎖是通過給索引項加鎖實現的。
這句話說明了什么?
說明了一件事:只有通過索引條件檢索數據時,InnoDB 才使用行鎖,否則使用表鎖。
是不是感覺很詫異,但是事實上就是這樣的。
InnoDB 級別的行鎖也是分成了兩種
- 共享鎖
- 獨占鎖
共享鎖和獨占鎖(Shared and Exclusive Locks),InnoDB 通過共享鎖和獨占鎖兩種方式實現了標準的行鎖。共享鎖(S 鎖):允許事務獲得鎖后去讀數據,獨占鎖(X 鎖):允許事務獲得鎖后去更新或刪除數據。一個事務獲取的共享鎖 S 后,允許其他事務獲取 S 鎖,此時兩個事務都持有共享鎖 S,但是不允許其他事務獲取 X 鎖。如果一個事務獲取的獨占鎖(X),則不允許其他事務獲取 S 或者 X 鎖,必須等到該事務釋放鎖后才可以獲取到
很多讀者肯定也都了解的很深入,肯定還有其他的,對,還有一種就是意向共享鎖和意向獨占鎖。
這種意向共享鎖和意向獨占鎖的意思就是如果我需要一個共享鎖,但是這個共享鎖這時候正鎖定這資源,那我自己就可以加一個共享鎖,只能等這個共享鎖釋放之后,我才能鎖定,這個鎖就可以稱之為意向共享鎖,同理,獨占鎖也是一樣的。
而他們之間的邏輯關系是這個樣子的。
數據庫鎖表的原因
其實最簡單的就是會出現在 insert、update、delete 這些操作的并發操作上,當我們使用多個數據庫連接的時候,同時對一個表中的數據進行更新的操作的時候,那么速度就會對應的變慢,如果持續一段時間之后,那么就會出現鎖表的現象了。
那么都有哪些操作會導致出現鎖表呢?
(1) 插入查詢的語句
- insertintotablevaluesselectxxxxfromtable2
這種情況就會鎖住table2.
(2) 更新并發操作
- updatetable1table2settable1.name=‘xxx’wheretable1.id=table2.id
這樣也會導致鎖表。
怎么樣降低鎖表的情況?
MyISAM表鎖的優化:
- 縮短鎖定的時間:這么說吧,實際上最簡單的就是加索引,讓你的索引利用最大化,
- 合理利用讀寫優先級:寫優先,讀其次。
Innodb行鎖的優化
- 加索引,讓查詢走索引
- 學會控制事務
- 隔離級別不要隨便設置,根據不同情況不同選擇就可以了