為什么要鎖
當多個用戶并發(fā)地存取數(shù)據(jù)時喻旷,在數(shù)據(jù)庫中就會產(chǎn)生多個事務同時存取同一數(shù)據(jù)的情況记劝。若對并發(fā)操作不加控制就可能會讀取和存儲不正確的數(shù)據(jù),破壞數(shù)據(jù)庫的一致性(臟讀,不可重復讀乾戏,幻讀等),可能產(chǎn)生死鎖白粉。為了解決這個問題讯壶,加鎖是一個非常重要的技術(shù),對實現(xiàn)數(shù)據(jù)庫并發(fā)控制是一個好的方案状婶。簡單說意敛,當一個執(zhí)行sql語句的事務想要操作表記錄之前膛虫,先向數(shù)據(jù)庫發(fā)出請求草姻,對你訪問的記錄集加鎖,在這個事務釋放這個鎖之前稍刀,其他事務不能對這些數(shù)據(jù)進行更新操作撩独。
MySQL存儲引擎
對比項 | MyISAM | innoDB |
---|---|---|
主外鍵 | 不支持 | 支持 |
事務 | 不支持 | 支持 |
行表鎖 | 表鎖。操作一條記錄也會鎖住整個表 | 行鎖。操作時只鎖某一行 |
緩存 | 只緩存索引跌榔,不緩存真實數(shù)據(jù) | 不僅緩存索引异雁,還緩存真實數(shù)據(jù) |
表空間 | 小 | 大 |
關(guān)注點 | 性能 | 事務 |
默認安裝 | Y | Y |
-- mysql現(xiàn)在已提供什么存儲引擎:
mysql> show engines;
-- mysql查詢當前默認的存儲引擎
mysql>show variables like '%storage_engine%';
-- 要看某個表用了什么引擎
mysql> show create table 表名;
行級鎖
防止另外事務修改此行
支持存儲引擎:
- mysql默認存儲引擎 InnoDB(默認行級鎖)
- 分布式存儲引擎 NDBCluster
行級鎖類型:
- 共享鎖
名詞解釋: 共享鎖又叫做讀鎖,所有的事務只能對其進行讀操作不能寫操作僧须,加上共享鎖后在事務結(jié)束之前其他事務只能再加共享鎖纲刀,除此之外其他任何類型的鎖都不能再加了。也就是我讀取的行担平,你不能修改
用法: SELECTid
FROM table WHERE id in(1,2) LOCK IN SHARE MODE 結(jié)果集的數(shù)據(jù)都會加共享鎖
- 排他鎖
名詞解釋: 若某個事物對某一行加上了排他鎖示绊,只能這個事務對其進行讀寫,在此事務結(jié)束之前暂论,其他事務不能對其進行加任何鎖面褐,其他進程可以讀取,不能進行寫操作,需等待其釋放取胎。也就是我更新的行展哭,不允許其他的事務讀取和更新相同的行;
用法: SELECTid
FROM table WHERE id=1 FOR UPDATE
特點:
開鎖大闻蛀,加鎖慢匪傍;會出現(xiàn)死鎖;鎖定粒度最小觉痛,發(fā)生鎖沖突的概率最低役衡,并發(fā)度也最高。適合于有大量按索引更新少量不同數(shù)據(jù)薪棒,同時又有并發(fā)查詢的應用手蝎,如一些在線事務處理系統(tǒng)
表級鎖
表示對當前操作的整張表加鎖
支持存儲引擎:
- MYISAM
- INNODB
行級鎖類型:
表共享讀鎖(共享鎖)
表獨占寫鎖(排他鎖)
特點
開銷小,加鎖快俐芯;不會出現(xiàn)死鎖棵介;鎖定粒度大,發(fā)出鎖沖突的概率最高吧史,并發(fā)度最低鞍时。
悲觀鎖(排它鎖)
每次去拿數(shù)據(jù)的時候都認為別人會修改,所以每次在拿數(shù)據(jù)的時候都會上鎖扣蜻,這樣別人想拿這個數(shù)據(jù)就會block直到它拿到鎖
傳統(tǒng)的關(guān)系型數(shù)據(jù)庫里邊就用到了很多這種鎖機制逆巍,比如行鎖,表鎖等莽使,讀鎖锐极,寫鎖等,都是在做操作之前先上鎖芳肌。
樂觀鎖
每次去拿數(shù)據(jù)的時候都認為別人不會修改灵再,所以不會上鎖肋层,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數(shù)據(jù),可以使用版本號等機制
樂觀鎖適用于多讀的應用類型翎迁,這樣可以提高吞吐量栋猖,像數(shù)據(jù)庫如果提供類似于write_condition機制的其實都是提供的樂觀鎖
樂觀鎖實現(xiàn): 大多數(shù)基于數(shù)據(jù)版本(Version)記錄機制實現(xiàn)
具體可通過給表加一個版本號或時間戳字段實現(xiàn),當讀取數(shù)據(jù)時汪榔,將version字段的值一同讀出蒲拉,數(shù)據(jù)每更新一次,對此version值加一痴腌。當我們提交更新的時候雌团,判斷當前版本信息與第一次取出來的版本值大小,如果數(shù)據(jù)庫表當前版本號與第一次取出來的version值相等士聪,則予以更新锦援,否則認為是過期數(shù)據(jù),拒絕更新剥悟,讓用戶重新操作灵寺。
悲觀鎖 和 樂觀鎖的區(qū)別
兩種鎖各有優(yōu)缺點,不可認為一種好于另一種区岗,像樂觀鎖適用于寫比較少的情況下替久,即沖突真的很少發(fā)生的時候,這樣可以省去了鎖的開銷躏尉,加大了系統(tǒng)的整個吞吐量。但如果經(jīng)常產(chǎn)生沖突后众,上層應用會不斷的進行retry胀糜,這樣反倒是降低了性能,所以這種情況下用悲觀鎖就比較合適蒂誉。
死鎖
所謂死鎖<DeadLock>: 是指兩個或兩個以上的進程在執(zhí)行過程中,
因爭奪資源而造成的一種互相等待的現(xiàn)象,若無外力作用,它們都將無法推進下去.
此時稱系統(tǒng)處于死鎖狀態(tài)或系統(tǒng)產(chǎn)生了死鎖,這些永遠在互相等竺的進程稱為死鎖進程.
表級鎖不會產(chǎn)生死鎖.所以解決死鎖主要還是針對于最常用的InnoDB.
++死鎖的關(guān)鍵在于:兩個(或以上)的Session加鎖的順序不一致教藻。++
解除死鎖狀態(tài)
解除正在死鎖的狀態(tài)有兩種方法:
第一種:
1.查詢是否鎖表
show OPEN TABLES where In_use > 0;
2.查詢進程(如果您有SUPER權(quán)限,您可以看到所有線程右锨。否則括堤,您只能看到您自己的線程)
show processlist
3.殺死進程id(就是上面命令的id列)
kill id
第二種:
1.查看下在鎖的事務
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
2.殺死進程id(就是上面命令的trx_mysql_thread_id列)
kill 線程ID
其它關(guān)于查看死鎖的命令:
1:查看當前的事務
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
2:查看當前鎖定的事務
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
3:查看當前等鎖的事務
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;