- PR -

OracleJDBC使用時のトランザクションの原子性の実現について

投稿者投稿内容
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2008-02-17 23:33
引用:

unibonさんの書き込み (2008-02-17 23:16) より:
ということは、コミットされても文句は言えない?


SQLException に対するエラー処理を catch や finally でおこなう際に、リソースを解放するために Connection#close をしたくなりますが、その際にいっしょに Connection#rollback をしないと、コミットされても文句を言えないのかなあ、とも思います。
すなわち close するなら rollback もかならずしないと JDBC Driver の実装依存になってしまうとも考えますが、どうでしょうか。(また close さえしなければリソースは解放されないかもしれませんが、コミットされることはない、とも考えます。)

ちなみに、
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=10297&forum=12
では、Statement と ResultSet についての話ですが、Connection とは扱いが違うのかどうかなどはちょっと分かりませんでした。
会議室デビュー日: 2008/02/17
投稿数: 6
投稿日時: 2008-02-18 00:18
ご回答ありがとうございます。

>ほったてさま
引用:
どっからそんな話が出たのか不明ですが...。ってかその「ゴミ」とやらは本当にデータの話なんでしょうかね。


そう言っている人がいたのですが、実際にその人が経験したのかどうかは定かではありません。私もその主張が信じられずネット上の文献をある程度探したのですが、意外なことにRDBMSでの原子性の実装についてはwikpediaなどで大雑把な手法は述べられていましたが細かい挙動について明確に述べているソースは見つかりませんでした。(Oracleのサイトも含めて)

>unibonさま
引用:
すなわち close するなら rollback もかならずしないと JDBC Driver の実装依存になってしまうとも考えます


私の質問の意図はこのような時のJDBCドライバの実装がrollback()をしない仕様であったり、またはrollback()する仕様で試みたが失敗したときにDBMS側で自主的に障害を検知してJDBCドライバからの命令がなくてもrollbackしてくれるのかを明確に知りたいというものです。

unibonさまがjavadocから引用された
引用:
close メソッドの呼び出し前に、アプリケーションでアクティブなトランザクションを明示的にコミットまたはロールバックすることを強くお勧めします。


という文章が今分かる範囲での結論であるように思います。

みなさまの見解が私の見解(通常考えうる確率ではゴミは残らない)と一緒であるように感じられて安心しました。

実績のあるRDBMSでも原子性を完全に実装するのは困難なことだとは思いますが、RDBMSベンダの原子性実装を放棄して、私の作成するJavaアプリでロールバックを実装することは(それによってリスクが減ることはまずあり得ない、というかそのような処理でautoCommit(true)にしていたら通常はリスクが高くなるので)やはりナンセンスだと思いました。
整合性を要求する複数のinsert, update文はまとめて実行し、catch節でrollback()をし、それに失敗したらログに出力するといった実装が妥当だという見解です。(そして通常はrollback()に失敗してもDBMS側で自主的にロールバックされていることを期待する。万一ロールバックされていなかった場合はログから状況を把握するしかないが、この可能性はほとんどないと認識する。)

引き続きご指摘やご経験等ございましたらご教授いただけると幸いです。
忠犬
大ベテラン
会議室デビュー日: 2006/05/01
投稿数: 109
投稿日時: 2008-02-18 08:06
RDBMSというかDBMSの常識としては、明示的にCOMMITするかトランザクションが
正常終了するとCOMMITされます。

明示的にROLLBACKしたり、トランザクションが異常終了すると、更新内容は無効に
なります。

ROLLBACKが失敗するということは、ほったてさんも書いているように異常事態で
あり、バックアップからの回復といった手段になると思います。
カーニー
ぬし
会議室デビュー日: 2003/09/04
投稿数: 358
お住まい・勤務地: 東京
投稿日時: 2008-02-18 11:46
例えばrollback()でSQLExceptionが返ってきたら、そのアプリはどう対応しますか?
Connection.close()しますかね? 単にトランザクションを中断してコネクションプールに返すことになりますかね?

前者ならトランザクションの状態が確定しないままセッション断ですから、セッション終了時にロールバックされますね。でも、rollback()が失敗するくらいだから、close()も失敗するかもしれませんね。その場合、既にセッションは無効になっているのでしょうから、理由はどうあれ、どっかのタイミングでOracleがきれいにクリーンアップしてくれるはずです。

コネクションプールに返した場合は・・・プールの実装とか設定に依存するかも。
別の処理がそのConnectionオブジェクトをプールから取り出して、ロールバックできなかったトランザクション内で処理を開始してしまう可能性はあると言えばありますよね。

でも普通に考えれば、rollback()のような基本的なメソッドがエラーを返す場合、そのセッションに大きな異常が発生していると考えられますから、そのConnectionオブジェクトはその後何をやってもエラーになる可能性が非常に高いでしょう。
プールからConnectionを取り出す度に、Connectionが有効かどうかをチェックしているようなら、その時に廃棄されるでしょうし、他の処理が使おうとしても何もできずにエラーになるだけ。

自分はrollback()の失敗の可能性に関しては、特に何の考慮もしていません。
カーニー
ぬし
会議室デビュー日: 2003/09/04
投稿数: 358
お住まい・勤務地: 東京
投稿日時: 2008-02-18 11:51
前の投稿とちょっとかぶりますが、念のため。
引用:

忠犬さんの書き込み (2008-02-18 08:06) より:
ROLLBACKが失敗するということは、ほったてさんも書いているように異常事態で
あり、バックアップからの回復といった手段になると思います。


N/W障害とか、Oracleの特定セッションや特定プロセスのみに障害が発生するとか、Oracle全体としてみれば大した事態ではないことがほとんどだと思います。
ほったて
ベテラン
会議室デビュー日: 2007/11/10
投稿数: 68
投稿日時: 2008-02-18 18:33
引用:

カーニーさんの書き込み (2008-02-18 11:51) より:

N/W障害とか、Oracleの特定セッションや特定プロセスのみに障害が発生するとか、Oracle全体としてみれば大した事態ではないことがほとんどだと思います。



そっか、ネットワーク切れてればrollback投げても実行できませんな...。
会議室デビュー日: 2008/02/17
投稿数: 6
投稿日時: 2008-02-18 23:26
興味深いご回答ありがとうございます。

引用:

カーニーさんの書き込み (2008-02-18 11:46) より:
コネクションプールに返した場合は・・・プールの実装とか設定に依存するかも。



この話題はDBMSの実装やコネクションプールの実装に依存しているのでそのあたり気になるところではありますが、まずは常識的な実装がされていて気にする必要はないと考えてよい気がしました。

スキルアップ/キャリアアップ(JOB@IT)