附錄:前段時間學習了下innodb鎖的相關知識,對鎖和事務有了大致理解,這裏作個小總結。 mysql
Innodb區別於MyISAM的兩個特色就是Innodb對於事務的支持和對行鎖的支持。事務要求了一組SQL語句的ACID特性,同時爲了不對一行記錄的併發更新,innodb自己會在必定狀況下加鎖,而後等語句所在的事務退出後(rollbak或者commit)釋放鎖。其實在autocommit=true時,一個sql自己就是一個事務。 sql
Innodb在執行Update,Delete,Insert時會對記錄加寫鎖(排他鎖,加上排他鎖後,不能再加共享鎖和排他鎖)。而Select語句不會對記錄加鎖。 數據庫
共享鎖:SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE。 併發
排他鎖(X):SELECT * FROM table_name WHERE ... FOR UPDATE。 工具
舉例: 學習
如圖,左側事務加了排他鎖(for update),右側事務直接查詢不會等待(不加鎖),加排他鎖失敗,加共享鎖失敗(lock in share mode)。左側事務提交或者回滾後,釋放鎖。 優化
Innodb使用行鎖加鎖記錄,也就是說會在加鎖條件下對訪問的具體行進行加鎖,而不會鎖住全表。這樣可以大大提升表訪問的吞吐量,減小沒必要要的記錄鎖。而Innodb的行鎖是使用索引實現的,所以有一下幾點須要注意: spa
如圖 線程
左邊事務鎖住了age>3的記錄,那麼很天然age=4的記錄會被鎖住。而在右邊事務中,插入一條age=5個記錄,而插入操做被hang住,這就是間隙鎖。間隙鎖是爲了不幻象讀的發生,即A事務批量update condition=x的記錄,同時B事務插入了一條condition=X的記錄,那麼A事務提交後,發現仍然存在一條沒有更新的記錄,貌似出現了幻覺,這就是幻讀。 htm
由於間隙鎖彷佛爲了防止插入,因此update age=5並不鎖表,由於記錄並不存在- -。
例如:
learntransaction表在age加了索引,左邊窗口查詢age=122 AND id=6的記錄,右邊窗口查詢age=122 and id=3的記錄,能夠發現二者的記錄並不一樣,可是卻出現了鎖競爭,由於兩個公用了一個索引age=122。
當where語句的查詢字段涉及到多個索引時,mysql會優化sql決定走的索引,因此若是id也加了索引,那麼索然在where語句裏age在前面,但不必定走age的索引而走了id的索引。因此這個時候對於怎麼加鎖須要看具體索引的使用狀況,建議使用explain工具查詢執行計劃判斷。
這裏須要注意的是,慢查詢致使數據庫hang住並不必定是由於競爭鎖,慢查詢可能由於要更新的記錄太多,致使sql遲遲沒法完成,而innodb默認32個槽,也就是32個併發工做線程,當32個線程都在運行而沒法接收新的sql時,數據就可能被hang住了,而與鎖無關。
參考資料:
《深刻淺出MySQL——數據庫開發、優化與管理維護》 http://book.51cto.com/art/200803/68127.htm