2

私のプロジェクトでは、java、ibatic、および MySql を使用しています。

SELECT FOR UPDATEデータベースにデータを更新する前に、クエリでテーブルをロックします

eg: SELECT * FROM MEM_MST WHERE MEM_ID = #memId# FOR UPDATE

テーブルを適切にロックします。ただし、問題は、たとえば、2 つのクライアントが同時にテーブルを更新する場合です。1 つ目はテーブルをロックして更新しますが、2 つ目はロックが解除されるまで更新を待機します。その後、2 つ目もデータを更新します。ですので、最初の更新データは上書きです。次の説明を参照してください。

Time |  Client 1           | Client 2  
-------------------------------------------------
1    | SELECT FOR UPDATE   | 
2    | UPDATE              | SELECT FOR UPDATE (Waiting) 
3    | COMMIT              | (Waiting)
4    |                     | UPDATE
5    | (Overwritten)       | COMMIT

そのため、クライアント 1 の更新されたデータは失われます

私がしたいのは、ロックが解除されるまで待つのではなく、単にクライアント 2 にエラー メッセージを返したいということです。

上記の問題を解決する方法を教えてください。


PS:

起動変数で既にロック待機タイムアウトを 0 に設定していますが、「ロック待機タイムアウトを超えました」というメッセージが表示されるまでに約 2 秒かかります。

さらに、SELECT FOR UPDATE NO WAITMySQLでは機能しません

4

1 に答える 1

0

残念ながら、innodb_lock_wait_timeout1 未満に設定することはできません。

独自の同期メカニズムを実装する必要があります。egyal の提案に代わるものとして、重要なテーブルに「セマフォ」フィールドを追加することができます。基本的なワークフロー (疑似コード):

START TRANSACTION;
SELECT locked FROM MEM_MST WHERE MEM_ID = @id FOR UPDATE;
if (previous_result == 1) {
    ROLLBACK;
    throw new Exception();
}
UPDATE MEM_MST SET locked = 1 WHERE MEM_ID = @id;
COMMIT; -- from now on, concurrent attempts will fail immediately

START TRANSACTION;
UPDATE MEM_MST SET whatever = @some_value WHERE MEM_ID = @id;
UPDATE MEM_MST SET locked = 0 WHERE MEM_ID = @id; -- release lock
COMMIT;
于 2013-12-19T17:22:58.983 に答える