註明: 本文轉載自http://www.hollischuang.com/archives/914
在計算機科學中,鎖是在執行多線程時用於強行限制資源訪問的同步機制,即用於在併發控制中保證對互斥要求的知足。sql
在數據庫的鎖機制中介紹過,在DBMS中,能夠按照鎖的粒度把數據庫鎖分爲行級鎖(INNODB引擎)、表級鎖(MYISAM引擎)和頁級鎖(BDB引擎 )。數據庫
行級鎖是Mysql中鎖定粒度最細的一種鎖,表示只針對當前操做的行進行加鎖。行級鎖能大大減小數據庫操做的衝突。其加鎖粒度最小,但加鎖的開銷也最大。行級鎖分爲共享鎖和排他鎖.多線程
開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的機率最低,併發度也最高。併發
表級鎖是MySQL中鎖定粒度最大的一種鎖,表示對當前操做的整張表加鎖,它實現簡單,資源消耗較少,被大部分MySQL引擎支持。最常使用的MYISAM與INNODB都支持表級鎖定。表級鎖定分爲表共享讀鎖
(共享鎖)與表獨佔寫鎖
(排他鎖)。性能
開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發出鎖衝突的機率最高,併發度最低。線程
頁級鎖是MySQL中鎖定粒度介於行級鎖和表級鎖中間的一種鎖。表級鎖速度快,但衝突多,行級衝突少,但速度慢。因此取了折衷的頁級,一次鎖定相鄰的一組記錄。BDB支持頁級鎖code
開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,併發度通常htm
MyISAM和MEMORY採用表級鎖(table-level locking)索引
BDB採用頁面鎖(page-level locking)或表級鎖,默認爲頁面鎖事務
InnoDB支持行級鎖(row-level locking)和表級鎖,默認爲行級鎖
前面提到過,在Innodb引擎中既支持行鎖也支持表鎖,那麼何時會鎖住整張表,何時或只鎖住一行呢?
InnoDB行鎖是經過給索引上的索引項加鎖來實現的,這一點MySQL與Oracle不一樣,後者是經過在數據塊中對相應數據行加鎖來實現的。InnoDB這種行鎖實現特色意味着:只有經過索引條件檢索數據,InnoDB才使用行級鎖,不然,InnoDB將使用表鎖!
在實際應用中,要特別注意InnoDB行鎖的這一特性,否則的話,可能致使大量的鎖衝突,從而影響併發性能。
行級鎖都是基於索引的,若是一條SQL語句用不到索引是不會使用行級鎖的,會使用表級鎖。行級鎖的缺點是:因爲須要請求大量的鎖資源,因此速度慢,內存消耗大。
MyISAM中是不會產生死鎖的,由於MyISAM老是一次性得到所需的所有鎖,要麼所有知足,要麼所有等待。而在InnoDB中,鎖是逐步得到的,就形成了死鎖的可能。
在MySQL中,行級鎖並非直接鎖記錄,而是鎖索引。索引分爲主鍵索引和非主鍵索引兩種,若是一條sql語句操做了主鍵索引,MySQL就會鎖定這條主鍵索引;若是一條語句操做了非主鍵索引,MySQL會先鎖定該非主鍵索引,再鎖定相關的主鍵索引。 在UPDATE、DELETE操做時,MySQL不只鎖定WHERE條件掃描過的全部索引記錄,並且會鎖定相鄰的鍵值,即所謂的next-key locking。
當兩個事務同時執行,一個鎖住了主鍵索引,在等待其餘相關索引。另外一個鎖定了非主鍵索引,在等待主鍵索引。這樣就會發生死鎖。
發生死鎖後,InnoDB通常均可以檢測到,並使一個事務釋放鎖回退,另外一個獲取鎖完成事務。
有多種方法能夠避免死鎖,這裏只介紹常見的三種
一、若是不一樣程序會併發存取多個表,儘可能約定以相同的順序訪問表,能夠大大下降死鎖機會。
二、在同一個事務中,儘量作到一次鎖定所須要的全部資源,減小死鎖產生機率;
三、對於很是容易產生死鎖的業務部分,能夠嘗試使用升級鎖定顆粒度,經過表級鎖定來減小死鎖產生的機率;