質問
selectを実行してから、 ResultSet
の行の一部をアトミックに更新する必要があります。
使用しているコードは次のようになります(簡略化):
stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
rs = stmt.executeQuery("SELECT ...");
while (rs.next()) {
if (conditions_to_update) {
rs.updateString(...);
rs.updateRow();
}
}
- 更新がアトミックに実行されることを保証できますか?そうでない場合、どうすればそれを保証できますか?
-
updateRow()
で更新しているデータベース行を他のプロセスが変更した場合はどうなりますか?ResultSet
の行をロックする方法はありますか?
解決
おそらくここにはたくさんのテクノロジーとコンセプトがあり、マルチスレッド/マルチリクエストアプリケーションを検討し始めると、物事はかなり厄介になり始めます。
Iassevkが述べたように、トランザクション更新のアトミックな性質を保証する-非常に低レベルの例は、次の行に沿って何かをすることです:
...
con.setAutoCommit(false);
try {
while (rs.next()) {
if (conditions_to_update) {
rs.updateString(...);
rs.updateRow();
}
}
con.setAutoCommit(true);
} catch (Exception ex) {
//log the exception and rollback
con.rollback();
} finally {
con.close();
}
その後、すべての更新が同じトランザクションにバッチ処理されます。更新のいずれかが例外を生成した場合(無効な値や結果の途中で接続が失敗した場合など)、ロット全体がロールバックされます。 (最後に私がそれを支持しているので追加しました; p)
ただし、これは、同じテーブルを更新しようとする2つの競合する方法(競合状態)である2番目の問題に対処しません。私の考えでは、ここには2つの主なアプローチがあります。それぞれにメリットとデメリットがあります。
最も簡単なアプローチは、テーブルをロックすることです-これは最小限のコード変更を必要としますが、かなり大きな欠点があります。ほとんどのアプリケーションと同様に、書き込みの方が読みやすいという仮定に基づいて作業します。テーブルをロックすると、他のすべてのユーザーがデータを表示できなくなります。キックして例外をスローします。
より複雑なアプローチは、これらの更新を実行するメソッドがスレッドセーフな方法で実装されるようにすることです。そのために:
- このテーブルのすべての更新は単一のクラスを通過します
- そのクラスはシングルトンパターンを実装するか、更新メソッドを静的メソッドとして公開します
- 更新メソッドは、同期キーワードを利用します競合状態を防ぐため
他のヒント
トランザクションを使用します。
updateRow()で更新しているデータベース行を他のプロセスが変更した場合はどうなりますか? ResultSetの行をロックする方法はありますか?
Oracleでは、次のSQLを発行することにより、特定の行を更新用にマークできます。
select cola, colB from tabA for update;
この行を更新しようとする次のトランザクション/スレッド/アプリは例外を取得します。詳細については、これを参照してください- http://asktom.oracle.com/pls/asktom/f?p=100:11:0:::::P11_QUESTION_ID:4530093713805