thinkphp中的lock與mysql的for update的使用注意事項


一、數據庫需要鎖表的場景

  1. 場景1,對於資金和商品數量,非常重要。在同一時間內必須只有一個連接能夠修改。
  2. 場景2:一個表A的值,依賴於表B的值,那么我在計算A更新值時,必須保證這個時間內,B表的值沒有發生變化

二、 在thinkphp框架鎖表的實現

  1. 使用模型類,調用lock()方法, 參數true是全局范圍的,false只是當前鏈接

  2. lock()調用會在sql語句后面,加上“for update”.

  3. lock生效的條件,必須方式一個事務中,可以使用所有表開啟Db::stratTrans(),Db::commit()之后鎖表結束

    • //單個表事務
      $user = new User();
      $db = $user->db(true);
      $db->startTrans();
      $res = $user->lock(true)->where(["id" => 1])->field('mobile,username')->find();
      sleep(3); // 休眠3秒,ID=1的行會鎖表3秒
      $db->commit();
      
    • //多個表事務
      Db::stratTrans();
      User::lock(true)->where(["id" => 1])->field('mobile,username')->find();
      sleep(3); // 休眠3秒,ID=1的行會鎖表3秒
      Db::commit();//或者回退也是戶釋放的,Db:rollback();
      
  4. lock生效過程中,其他的並發請求中的Update操作都會出於阻塞,等待的狀態

  5. lock使用的注意事項,lock的條件,一定要用主鍵唯一索引鍵,否則容易導致,整個表被鎖住,而導致其他服務都出於等待中。原因,下面會講。

三、mysql中for update

  1. for update是在數據庫中上鎖用的,可以為數據庫中的行上一個排它鎖。當一個事務的操作未完成時候,其他事務可以讀取但是不能寫入或更新。

  2. InnoDB默認是行級別的鎖,當有明確指定的主鍵時候,是行級鎖。否則是表級別。

  3. for update 僅適用於InnoDB,並且必須開啟事務,在begin與commit之間才生效。

  4. 鎖的具體實例,假設表foods ,存在有id跟name、status三個字段,id是主鍵,status有索引。

    1. 明確指定主鍵,並且有此記錄,行級鎖

      SELECT * FROM foods WHERE id=1 FOR UPDATE;
      SELECT * FROM foods WHERE id=1 and name=’咖啡色的羊駝’ FOR UPDATE;
      
    2. 明確指定主鍵/索引,若查無此記錄,無鎖

      SELECT * FROM foods WHERE id=-1 FOR UPDATE;
      
    3. 無主鍵/索引,表級鎖。影響非常大

      SELECT * FROM foods WHERE name=’咖啡色的羊駝’ FOR UPDATE;
      
    4. 主鍵/索引不明確,表級鎖。影響非常大

      SELECT * FROM foods WHERE id<>’3’ FOR UPDATE;
      SELECT * FROM foods WHERE id LIKE ‘3’ FOR UPDATE;
      
  5. for update nowait 鎖住表或者鎖住行,只允許當前事務進行操作(讀寫),其他事務被拒絕,事務占據的statement連接也會被斷開


免責聲明!

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



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