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