2016-06-20 6 views
1

私は、次のコードは、同時に複数のスレッドで実行された場合はどうなるのデータアップデート - 分離

[Shirt, 1, 0] 
[Shorts, 10, 0] 

でモデル

Inventory [product_name, quantity, reserved_quantity] 

を以下のがありますか?

$changes = [ 
      ['name' => 'Shirt', 'qty' => 1], 
      ['name' => 'Shorts', 'qty' => 1], 
      ]; 
$db->startTransaction(); 
foreach($changes as $change){ 
    $rowsUpdated = $db->exec("UPDATE inventory 
      SET reserved_quantity = reserved_quantity + $change['qty'] 
      WHERE product_name = $change['name'] 
       and quantity >= reserved_quantity + $change['qty']"); 
    if($rowsUpdated !== 1) 
     $db->rollback(); 
     exit; 
} 
$db->commit(); 

結果はどうなりますか?

[Shirt, 1, 2] 
[Shorts, 10, 2] 

答えて

1

そうではありません。 は、次のシナリオで起きられるかを見ることができます:

  1. 最初トランザクションが開始
  2. UPDATEシャツ排他行ロックは、レコードに設定されます=>
  3. トランザクションが開始されます
  4. 第2トランザクションが試みますUPDATEシャツ。それはそれをロックレコードを取得する必要がありますように、このレコードがすでに最初トランザクションがコミット最初取引
  5. によってロックされているように待って、 1は、実行を再開し、更新されたレコード
  6. を見るでしょう

もちろん、InnoDbなどのMySQLエンジンにのみ関連します。 あなたは同じ順序でレコードをたどるほど幸運なことに注意してください。それ以外の場合は、deadlock

+0

ありがとうございました!したがって、トランザクションのコミットまたはロールバックが行われない限り、行ロックはそこにあります。これは、select for updateで明示的に要求しなくても可能です。 – user3625393

+0

はいhttp://dev.mysql.com/doc/refman/5.7/en/innodb-locks-set.html – ffeast

+0

ありがとうございます!あなたが正しい。私はちょうどプロトタイプを作って、あなたが述べたように動作します。 – user3625393