mysql for update 鎖行的錯誤理解


1. 最開始的理解是 : for update 會對查詢出的結果加行鎖,沒有查詢到結果就不加鎖。 

但是今天發現有一句代碼執行for update 卻超時了 。查了mysql 獲取鎖超時時間是 50s . 

已我目前業務量不可能有 某一行 被單獨鎖定50s 。 除非是整表有鎖,導致獲取單獨行鎖超時。

排查發現的確是表鎖。 

正確鎖行的理解: for update 會對 經過索引(包含主鍵, 此處注意《經過索引》,下面會說明)查詢出的結果行 加行鎖,否則就會加表鎖。 

舉例:表 t_log  , 主鍵 sys_uuid , 普通索引列 mer_order_no , 普通列 chk_trans_no  。 列類型都是Varchar

sys_uuid mer_order_no chk_trans_no
1 1 1
2 2 2

以下需要開啟兩個命令行,navicat 在tools - console 下。 C1- 命令行1 , C2 - 命令行2 

1. C1:   start transaction ; select * from t_log where chk_trans_no= 1  for update;   (開啟事務不commit)

    C2:      select * from t_log where chk_trans_no= 2  for update;  

  發現C2 卡住,C1 commit 后就執行了。  說明 對非索引列使用 for update  是表鎖

 

2. C1:   start transaction ; select * from t_log where mer_order_no = 1  for update;  

    C2:      select * from t_log where mer_order_no = 2  for update;  

  發現C2 仍然卡住 , mer_order_no 是索引列 啊 , 這是為何?原因在類型Varchar ,  數字1 會導致mysql 自動執行

類型轉換,而自動類型轉換索引失效(可以使用 explain sql 看清楚), 所以我上面強調是通過索引查詢出的結果, 而

這時候並不是通過索引查詢出的行,所以加的是表鎖。  

把1 和 2  換成 ‘1’ , '2' 。 C2 就不會卡住了,說明是行鎖。 

 

其他說明: 對一張表加行鎖后, 在想加表鎖,需要等待行鎖釋放。 

C1:   start transaction ; select * from t_log where mer_order_no = ‘1’  for update;  

C2:   select * from t_log where chk_trans_no= 2  for update;  (由於無索引會嘗試加表鎖,等待C1 釋放)

 

  綜上: 請慎用for update , 如果用請配置好索引。

 

 參考: https://www.cnblogs.com/liangge0218/archive/2013/03/26/3292381.html

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM