mysql 5.7をストレージエンジンと共にinnodbとして使用する。私は製品情報を格納するテーブルを持っています。テーブルには、商品コードに一意のキーで次のようになりますデッドロックにつながる行のMysql同時更新
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+-------------------+-----------------------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| productId | varchar(50) | NO | UNI | NULL | |
| seller | varchar(100) | NO | MUL | NULL | |
| updatedAt | timestamp | NO | MUL | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| status | varchar(100) | NO | MUL | NULL | |
| data | longtext | NO | | NULL | |
+-----------+--------------+------+-----+-------------------+-----------------------------+
私はこれのmysqlに接続されたJavaアプリを経由して2つの操作があります(製品の変更に関する情報が含まれています)
1.新規の着信イベントへのProductID必要性についてそれらが既存のイベントよりも大きなバージョンを持っている場合に挿入されます。バージョンはデータ列にjson blobとして保存されます
2.ステータスを変更するproductIdの行を更新します。
私の隔離レベルは読み込みコミットされています。 私は2つのアプローチを試みたが、両者がデッドロックにつながるされています
Approach1:
Transaction1 starts
Insert ignore into products where productId='X' values(); // Takes a S lock on the row
select * from products where productId='X' for update ; // Take a X lock on the row to prevent new writes and compare the incoming event with the current event
Insert into products values on duplicate key update values // insert into row and on duplicate key update values
commit
同時更新が別のトランザクションを開きます:
Transaction2 starts
select * from products where productId='X' for update ; // Take a X lock on the row to prevent new writes and compare the incoming event with the current event
Insert into products values on duplicate key update values // insert into row and on duplicate key update values
commit;
この状況でデッドロックにつながっています次の場合:
1.トランザクション1 - 挿入無視ステートメントが行をSロックしました。
トランザクション2 - 行のXロックを取るために更新ステートメントが選択されています。
3.トランザクション1 - 更新ステートメントの選択は、行のXロックを取得しようとします。
これは、Sロックがトランザクション1によって保持され、トランザクション2がXロックを待機しており、トランザクション1がXロックを取得しようとするとデッドロックにつながるため、デッドロックになります。
アプローチ2:この状況でデッドロックにつながっている
Transaction 1 starts:
select * from products where productId='X' for update ; // If a row exists then it will be locked else I know it does not exist
Insert ignore into products where productId='X' values();
commit
Transaction 2 starts:
select * from products where productId='X' for update ; // If a row exists then it will be locked else I know it does not exist
commit
次
1.トランザクション1 - SELECT FOR UPDATE文は行のXロックを取ります。
トランザクション2 - 行のXロックを取るために更新ステートメントが選択されています。
3.トランザクション1 - 挿入文を無視するには、行にSロックを取るしようとしますが、トランザクション1のXロックがすでにそう
デッドロックにつながるロックを待っている、私は、同時処理する方法を知りたいです更新とデッドロックにつながることなく、新しいイベント(行の更新ではなく)を私のテーブルに挿入する。
1.ロックの順序はどうすればよいですか?
2.同時更新と新しい行挿入がデッドロックなしで機能することを確認する方法。
任意の助けをいただければ幸いです:)
また、削除されたトランザクションを再度適用してください。トランザクションにデッドロックやその他のエラーが発生する可能性があるため、これを行う準備が必要です。 –
あなたの提案に感謝@RickJames。はい、トランザクションの再開はオプションでした。しかし、これは繰り返しパターンであり、上記の解決策が問題を解決しました。一般的に、デッドロックには何がありますか?避けてはいけませんか? –
デッドロックを回避できます。そして私はそれらを避けるために_trying_に同意します。しかし、このフォーラムでは、すべてのデッドロックを回避できると思う人が多く、そうしようとすると時間がかかりすぎるように思えます。私はあなた自身の問題を解決してうれしいです。 –