0

2 つのスレッドが実行されているプログラムがあり、各スレッドには独自のデータベース JDBC 接続があり、以下のように同じデータベース テーブル A にアクセス/変更します。テーブル A には 2 つの列 (id、name) しかなく、主キーは id と name の組み合わせです。

statement stmt;

// first delete it if the record has exist in table
stmt.addBatch("delete from A where id='arg_id' and name='arg_name';");

// then insert it to table
stmt.addBatch("insert into A values (arg_id, arg_name);");

stmt.executeBatch();

2 つのスレッドが同じデータをテーブルに挿入する可能性があり、次の例外が発生しました。

java.sql.BatchUpdateException: Duplicate entry '0001-joey' for key 1
        at com.mysql.jdbc.Statement.executeBatch(Statement.java:708)
        at com.mchange.v2.c3p0.impl.NewProxyStatement.executeBatch(NewProxyStatement.java:743)
        at proc.Worker.norD(NW.java:450)

この問題を解決する方法を教えてください。ありがとうございました。

よろしく、ジョーイ

4

3 に答える 3

0

データベースに単純な楽観的ロック機構を導入してみませんか?

バージョン列を追加し、トランザクションの削除または更新を実行するときにバージョン番号を追跡します。

あなたのテーブルは次のようになります

create table test(
id int not null primary key,
name varchar,
rowversion int default = 0);

行を取得するたびに、行のバージョンを取得する必要があります。

update test set name='new name' rowversion=rowversion+1 where id=id and rowversion=retrieved row version;

削除も同様

delete from test where id=id and rowversion=retrievedRowVersion;

これは、dbms の同時実行管理機能を利用する単純なメカニズムです。楽観的ロックの詳細については、このリンクを確認してくださいhttp://en.wikipedia.org/wiki/Optimistic_concurrency_control#Examples

これは明らかに並行性管理の非常に単純な実装にすぎませんが、問題はこれらを考慮に入れる必要があります。

また、二重挿入の場合、トランザクションが拒否されたという事実は良いことです。つまり、重複したキーが挿入されないことを意味します。例外を処理し、何が起こったかをユーザーに通知するだけです。

于 2011-11-14T14:30:31.780 に答える
0

両方のステートメントをトランザクションにラップします。

BEGIN;
DELETE FROM a WHERE ...;
INSERT INTO a VALUES (...);
COMMIT;

テーブルが主キーのみで構成されている限り、この競合はテーブルが最後に変更されていない場合にのみ発生することに注意してください。列をさらに追加したい場合は、UPDATE ... WHERE構文を使用して値を変更する必要があると思います。

于 2011-11-14T12:23:20.690 に答える
0

何らかの同期を使用していますか? まず、テーブルを変更するコードを次のようにラップする必要があります。

synchronized(obj)
{
    // code
}

ここで、obj は両方のスレッドがアクセスできるオブジェクトです。テーブルの変更の正確なセマンティクスはわかりませんが、両方がIDを挿入する場合は、「グローバル」IDも保持し、各スレッドでアトミックにインクリメントして、両方が同じ値にならないようにする必要があります.

于 2011-11-14T12:23:23.723 に答える