FOR UPDATE
の代わりに LOCK IN SHARE MODE
を使用します 。 FOR UPDATE
他のトランザクションが行を読み取るのを防ぎます。 LOCK IN SHARE MODE
読み取りは許可しますが、更新はできません。
参照:MySQLマニュアル
------セッション1
START TRANSACTION;
SELECT * FROM test WHERE t=1 LOCK IN SHARE MODE;
UPDATE test SET NAME='irfandd' WHERE t=2;
COMMIT;
-----セッション2(もうブロックされていません:))
START TRANSACTION;
UPDATE test SET NAME='irfandd' WHERE t=4;
COMMIT;
更新:
テーブルにインデックスがないことに気付く t
に 、次の説明があります:
まず、トランザクションT1が行1をロックします SELECT * FROM test WHERE t=1 FOR UPDATE
で
次に、トランザクションT2はUPDATE test SET NAME='irfandd' WHERE t=4
を実行しようとします。 。影響を受ける行を見つけるには、行1を含むすべての行をスキャンする必要があります。 。ただし、これはロックされているため、T2はT1が終了するまで待機する必要があります。何らかの種類のインデックスがある場合は、WHERE t=4
インデックスを使用して、行1かどうかを判断できます t=4
が含まれています かどうかにかかわらず、待つ必要はありません。
オプション1: test.t
にインデックスを追加します 更新で使用できるようになります。
オプション2: LOCK IN SHARE MODE
を使用します 、これは読み取りロックのみを設定することを目的としています。残念ながら、このオプションはデッドロックを作成します。興味深いことに、T2トランザクションは実行され(行4を更新)、T1は失敗します(行2を更新)。 T1は行4を読み取りロックしているようです また、T2がそれを変更するため、トランザクション分離レベルが原因でT1が失敗します(デフォルトでREPEATABLEREAD
)。最終的な解決策は、トランザクション分離レベル<で遊ぶことです。 / a> 、READ UNCOMMITTED
を使用 またはREAD COMMITTED
トランザクションレベル。
最も単純なのはオプション1 、私見ですが、それはあなたの可能性次第です。