3

Java アプリケーションで、一連の DB ステートメントをアトミックかつ分離された方法で実行する必要があります。たとえば、アプリケーションは、あるテーブルからデータ行を読み取り、別のテーブルのデータ行を更新する必要があります。

QueryRunner queryRunner = new QueryRunner(); // DBUtils query runner

Object[] params = new Object[] { param };

Connection conn = null;
try {
    conn = ...; // get connection
    conn.setAutoCommit(false);
    result = queryRunner.query(conn, "select x, y, z from table1 where column1 = ?", new BeanHandler<SomeBean>(SomeBean.class), params);

    // logic to get value for update

    queryRunner.update(conn, "update table2 set p = ? where q = ?", some_value, some_id);
    conn.commit();
} catch (SQLException e) {
    //
} finally {
    DBUtils.closeQuietly(conn);
}

トランザクション管理は、上記のように、接続に対して自動コミットを false に設定し、後で明示的にコミットすることによって実現されます。しかし、上記のコードはマルチスレッド環境でも実行できます。また、2 つの DB ステートメント (選択と更新) を相互排他的に全体として実行することも必要です。

以下に示すように、そのメソッドで共有 Java Lock オブジェクトを使用する考えがあります。

クラスでは、

private Lock lock = new ReentrantLock(); // member variable

メソッドでは、

lock.lock();
try {
    conn = ...; // get connection
    conn.setAutoCommit(false);

    result = queryRunner.query(conn, "select x, y, z from table1 where column1 = ?", new BeanHandler<SomeBean>(SomeBean.class), params);

    // logic to get value for update

    queryRunner.update(conn, "update table2 set p = ? where q = ?", some_value, some_id);
    conn.commit();
} finally {
    DBUtils.closeQuietly(conn);
    lock.unlock();
}

問題を解決する能力があるようです。ただし、これがベストプラクティスであるかどうか疑問に思っており、これに対するより良い代替手段 (フレームワークなど) はありますか?

4

4 に答える 4

1

このような問題を処理するもう1つの方法は、すべてのデータベーストランザクションにシリアル化可能なトランザクション分離レベルを使用することです。これにより、トランザクションのセットは、実際には一度に1つずつ実行されることなく、一度に1つずつ実行されたかのように動作します。これを行う場合は、シリアル化の失敗をキャッチしてトランザクションを再試行するフレームワーク(SQLState 40001)を使用する必要があります。大きな利点は、トランザクション間の特定の相互作用について心配する必要がないことです。トランザクションが実行中の唯一のものであるときにトランザクションが正しいことを行う場合、どのトランザクションミックスでも正しいことを行います。

これが非常に簡単に機能するには、すべてのトランザクションがシリアル化可能である必要があることに注意してください。

于 2012-04-05T04:12:37.973 に答える
1

私の提案は、アプリケーションではなく、データベースにこれらのロックを管理させることです。これは、複数の JVM がコードを実行している場合を処理します。あなたが言及したロックメカニズムは、単一の JVM でのみ有効です。

これを達成する方法は、SELECT ... FOR UPDATE. これにより、選択した行がロックされ、トランザクションがコミットまたはロールバックされるとロックが解除されます。これはテーブル レベルのロックよりも優れています。これらの行は、現在の値を読み取るだけで更新は必要としない他のトランザクションによって読み取られる可能性があるためです。別のトランザクションがロックを取得しようとするとFOR UPDATE、最初のトランザクションが完了するまでブロックされます。

于 2012-04-04T16:27:07.953 に答える
1

必要な原子性を実現する唯一の方法は、データベースでストアド プロシージャを使用してデータを分離し、一度にすべてロックすることです。Java レベルでのロックは、データベースでのロックが簡単にできることを行うことができません。

于 2012-04-04T16:38:05.553 に答える
0

私の理解では、選択ステートメントと更新ステートメントを含むコードのブロックをスレッドセーフにしたいだけですか? これが、synchronized キーワードが使用される理由です。この質問はずっと前に尋ねられましたが、ここにメモしておきたいと思います。これらのコード行を同期ブロックの下に置きます。

于 2013-09-13T10:41:03.693 に答える