Javaアプリケーションで、アトミックにアブノーマルなDBステートメントのセットを実行する要件があります。&たとえば、アプリケーションはある表からデータ行を読み取り、別の表のデータ行を更新する必要があります。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();
}
それは一種の問題を解決することができるようです。しかし、これがベストプラクティスであり、このためのより良い代替手段(フレームワークなど)があるのだろうかと思いますか?
ありがとう、Hiro2k。私たちのアプリケーションはサーブレットコンテナで実行されており、単一のJVM内にあると私は信じている。 SELECT文が動作しているテーブル以外のテーブルの行を更新しているので、 'SELECT ... FOR UPDATE'が私のケースで動作しないかもしれません。 – Chen
そうですが、ロードバランシングやスケーリングのためにサーバーの別のインスタンスを追加することに決めた場合、この問題が発生します。 2番目のテーブルの行に 'SELECT ... FOR UPDATE'をメソッドの先頭に追加すると、他のテーブルは終了するまで待たなければなりません。 – Hiro2k
良い点、@ Hiro2k。私は私の使用事例を評価して、それらのすべてがカバーできるかどうかを見ていきます。 – Chen