MySQL鎖相關內容

MySQL的表鎖使用 lock table 表名 (read | write),...,語句來添加讀鎖或者寫鎖。通過unlock table;語句來釋放所有表鎖。在對錶加了表鎖時,這個連接就不能再操作其他表了(包括讀和寫)。簡而言之,就是讀鎖會阻塞寫,但是不會阻塞讀。而寫鎖則會把讀和寫都阻塞。

還有一點就是網上都說表鎖不會造成死鎖。我一直對此感到疑惑,我就想一個連接鎖了一個表,然後另一個連接鎖了另一個表。接着這兩個連接再分別去鎖對方已經鎖定的表,那不就造成死鎖了嗎?但是,通過我自己的實驗發現,原來在一個連接已經鎖了表的情況下,再去鎖其他的表,會把之前的表鎖先釋放掉,再去鎖新的表。也就是說,一個連接去鎖新的表的時候,它一定不佔有任何表,這樣就杜絕了死鎖。這纔是表鎖不會造成死鎖的真正原因。

InnoDB引擎默認在一個事務中使用行鎖,但是當那個表沒有對應索引或者索引失效時,就會從行鎖升級爲表鎖,導致併發度大幅降低。InnoDB的查詢都是有事務的,默認是autocommit=1,也就是每一條sql語句作爲一個事務。    

併發一致性會導致如下三個問題:

  1. 髒讀:事務1修改一個數據,事務2接着讀取到了這個修改後的數據。但是如果之後事務1撤銷了修改,那麼事務2讀到的數據就是錯誤的,髒的數據。
  2. 不可重複讀:事務2讀取了一個數據,接着事務1對這個數據進行了修改,事務1提交後,事務2再讀這個數據,就會得到與之前不同的結果。
  3. 幻影讀:事務2統計一個表的行數,接着事務1往這個表插入數據,事務1提交後,事務2再次統計這個表的行數,就會得到與之前不同的結果。

MySQL提供了四種隔離級別:

  1. 未提交讀(READ UNCOMMITTED):事務中的修改,即使沒有提交,對其它事務也是可見的。這個級別沒有解決任何的問題。
  2. 提交讀(READ COMMITTED):一個事務只能讀取已經提交的事務所做的修改。換句話說,一個事務所做的修改在提交之前對其它事務是不可見的。這個級別解決了髒讀。
  3. 可重複讀(REPEATABLE READ):保證在同一個事務中多次讀取同一數據的結果是一樣的。要提交了之後,才能讀取到其他事務修改的內容。這個級別解決了髒讀和不可重複讀。
  4. 可串行化(SERIALIZABLE):強制事務串行執行,這樣多個事務互不干擾,不會出現併發一致性問題。通過使用加鎖機制,確保同一時間只有一個事務執行。這個級別最嚴格,解決了髒讀、不可重複讀和幻影讀。

MySQL的默認隔離級別是可重複讀。一般來說,隔離級別越低,支持的併發度就越高,但是併發一致性問題就越嚴重。總之要在業務需求和性能之間進行權衡,來確定MySQL所使用的隔離級別。

  行鎖優化建議:

  1. 儘可能讓所有數據檢索都通過索引來完成,避免無索引行鎖升級爲表鎖。
  2. 合理設計索引,儘量縮小鎖的範圍。
  3. 儘可能較少檢索條件,避免間隙鎖。
  4. 儘量控制事務大小,減少鎖定資源量和時間長度。
  5. 儘可能低級別事務隔離。(因爲越高級別的事務隔離,併發度越低,性能也就越低)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章