いま、シリーズ化している「オブジェクト指向で開発の最初から最後までの手順例」で、そのうち、トランザクション処理が必要になってくるはずです(発注と発注明細)。
そこで、そのための「トランザクション処理方法」に関して、先回りして書いておきます。
■そもそも、トランザクション処理とは
トランザクション処理とは、複数の更新、削除、挿入処理を行うとき、すべての処理が成功したときだけ、その処理を実行し、一個の処理でも失敗したら、全部の処理を取り消して欲しい場合に使います。
すべての処理に関連がある場合などでは、必須の処理となります。
今回の場合、発注データ挿入に失敗したら、発注明細をキャンセルしないといけないし、逆に発注明細の挿入に失敗したら、発注をキャンセルしないといけないです。なので、発注と発注明細の間にトランザクション処理が必要です。
■一般的方法
複数のテーブル間の処理のため、トランザクション処理のスタートと終了(コミットやロールバック)は、個々のテーブル内(EJBだとエンティティBean)で行うのではなく、
その個々のテーブル操作より上の、複数のテーブルを操作する呼び出し部分(EJBだとセッションBean)で行います。
一般的に、以下の手順で行います
・コネクションを作成します ・個々のテーブルで、更新処理をします ・エラーが起きたら、トランザクションキャンセルし、 コネクションをクローズして、更新処理を終了します : (以降、更新分、この処理をします) : ・コミット処理を行い、失敗したらロールバックします いずれにせよ、コネクションをクローズします。 |
各テーブルの更新処理においては、初めに作成したコネクションを受け渡しして、それを使って、更新、削除、挿入などの処理をします。このコネクションなど(ステートメントまでももっておいてもいいし、検索用にPreparedStatementを持つ場合もあります)は、Contextクラスというのを自分で作って、そこに入れるのがふつうです。
■トランザクションの入れ子の問題
ただ、呼び出し部分=MVCだとモデル部分のメソッド全部にトランザクション処理を入れると、モデルの中で、モデルを呼び出している場合、トランザクションの入れ子になってしまいます。
入れ子処理ができるものもありますが、そもそも、自分で何がどーなっているのかわかんなくなってくるので(ウィリアムのいたずらが頭悪いだけ ^^;)
入れ子処理をさせないほうがいい場合もあります。
この対応としては、コンテキストの中身がNULL(トランザクションスタートのとき)は、コンテキストを生成し、生成した場合は、そのモジュールで、commitまたはロールバックします。
逆に、コンテキストの中身に、コネクションなどが入っていたら、それは入れ子ということで、そのコネクションを使って、処理を行い、エラーがきたら、返り値にエラーを返して抜けます(エラーを受け取り、ロールバックするのは、呼び出し側の仕事)
■そこで、カオル姫方式を使う
現在、自動生成しているDBアクセス部分は、ハッシュマップを引数にしているので、こいつにコネクションを入れます。
呼び出し方のモデル部分も、入れ子の場合、コネクションを受け渡しすることになります。
ただ、面倒なので、モデル部分の引数を、ハッシュマップにしてしまえば、DBアクセス部分同様、ハッシュマップにコネクションが入れられます
(コネクションが入ってないハッシュマップだった場合、それが一番の上位になるので、そこで、コネクションを生成して、ハッシュマップを作ります)
詳しい話というか、具体例は、「オブジェクト指向で開発の最初から最後までの手順例」の該当箇所で書く予定です(今後)