- PR -

DB周りのクラス設計

投稿者投稿内容
Tol
常連さん
会議室デビュー日: 2004/07/16
投稿数: 27
投稿日時: 2007-01-30 21:31
データベース周りのクラス設計について教えてください。

いろいろなサイトを調べてみると、DBアクセスの部分はDaoクラスに
記述するとなっているんですが、Daoクラスにトランザクション処理を
含めてしまうと、Daoを組み合わせることができません。
かといって、トランザクションなどのDB部分を業務ロジックに記述することは
よくないとなっていますが、みなさんはどのようにDaoを設計されているのでしょうか?

また、仮にトランザクションをDaoに含めて業務ロジックから隠しても
今度は別の問題がでてきます。
それは、Daoクラスに業務ロジックを含めることもよくないため、
DBアクセス(トランザクション)と業務ロジックが一体化したような
処理を行う際にどうやっていいかわかりません。
たとえば、以下のようなコードです。

コード:
void update(List<Integer> infoList) {
    // リストに含まれているすべての数字に対して処理を行う。
    for (Integer a : infoList) {
        // 数値をキーにテーブルを検索し、あるカラムの値を取得。
        int value = conn.executeQuery("select xxx from xxx where column = " + a);
    // カラムの値により場合わけ。
        if (value == 0 ) {
            System.err.println("エラー1です。");
        }
        else if (value == 1) {
            System.err.println("エラー2です");
        }
        else {
           // 0と1以外の場合はテーブルをアップデートする。
            conn.executeUpdate("update xxx set column1 = 1 where column2 = " + value);
        }
    }
    conn.commit();
}



上記のようなコードは、検索→判定→更新を繰り返し、すべて終了してコミットします。そのため、判定の際の業務ロジックはどうしても混じってしまいます。
このようなコードを上手に設計するためにはどうしたらよいのでしょうか?
一番簡単なのは、トランザクションの管理は業務ロジックに任せることだと思うのですが、どうなのでしょうか?
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2007-01-30 22:19
設計思想の問題なので正解というのはありません。

(とりあえず、私の思想)
・DAOの層では低レベルなデータ処理を行う
・業務ロジックはアトミックなDAOの利用の組み合わせ
と考えます。

例えばテーブルAとテーブルBとテーブルCがあり、
Dao_AとDao_BとDao_Cが存在するとします。
Daoとテーブルは1対1で存在して、
Daoはそれぞれのテーブルに対するCRUDを受け持ちます。

ある業務XはテーブルAを更新してからテーブルBを更新し、
ある業務YはテーブルBを更新してからテーブルCを更新するとした場合、
それぞれのDaoでトランザクション処理を行うことが出来なくなります。

つまり、自然と業務ロジック側でトランザクション処理を行う必要が出てきます。
したがって、トランザクション処理を行う場所は業務ロジック以外では在り得ないと考えます。

ちなみに、1つのDaoで複数のテーブルに対する処理を行う場合、
それは業務ロジックであって、Daoではないという前提です。
るぱん
ぬし
会議室デビュー日: 2003/08/01
投稿数: 1370
投稿日時: 2007-01-31 10:32
引用:

かつのりさんの書き込み (2007-01-30 22:19) より:

つまり、自然と業務ロジック側でトランザクション処理を行う必要が出てきます。
したがって、トランザクション処理を行う場所は業務ロジック以外では在り得ないと考えます。

ちなみに、1つのDaoで複数のテーブルに対する処理を行う場合、
それは業務ロジックであって、Daoではないという前提です。


るぱんです。

>かつのりさん
個人的に確認したいのですが、
そのとき、クラス名称はどのようにされてますか?
個人的には、BusinessLogicLayerが持つ擬似Daoみたいな扱いにしてましたが。。。汗
もちろん、Interfaceも設けると言った感じですが。
ご教示願います。
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2007-01-31 10:52
O/Rマッピングを使った設計だと、DBはMementパターンでの
データの保管先ぐらいに考えるのがよいのかな、と思っています。

DBでやれることはDBでやってしまおうという設計は
パフォーマンスチューニング的には惹かれるものがあるのですが
システム構成の柔軟性に難があるといいますか。
もっとも、DBを選ばないシステムにする必然性がどの程度あるか
という話が先に来るわけですけども。

そして、DBとの付き合い方の方針がはっきりしないことには
設計の方針もはっきりしないのだろうなと思います。

かつのり氏の提示の設計方法だとDBへの依存が少なくなる方法論ですよね。
もっともDB屋さんからすれば処理効率の悪そうな方法論に見えるかもしれませんが…。
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2007-01-31 10:56
その辺を扱うための機構は色々ありますよ。
JTAやEJBのCMT、SpringのTransaction Propagationです。

どれもトランザクションをスレッドに関連付けてます。
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2007-01-31 13:24
>るぱんさん

#余談も混ざっていますが・・・

私の場合、DaoクラスはHogeというテーブルに対して
HogeDaoという命名をしています。
それに対応するJavaBeanはHogeという命名をしています。

設計は、EclipseのClayプラグインを使っていまして、
テーブル設計でもテーブル名=クラス名、
カラム名=プロパティ名となるようにしています。

Clayの保存データがXMLなので、
リバースしてDaoとJavaBeanを機械的に生成しています。

複数テーブルに跨る処理の場合は業務ロジックです。といいましたが、
効率化のために一部例外を設けています。
それらはストアドやビューで実装しているのですが、
それらに対してもDaoとJavaBeanの組み合わせを作って対処しています。

効率化が必要な部分では業務ロジックとはみなさず、
仮想的なエンティティとみなす感じです。
この部分においては、Piyoというストアドであれば、
PiyoDaoというDaoと、PiyoというJavaBeanの組み合わせを作ります。

したがって、業務ロジック側のクラスは極普通のクラス名です。



>あしゅさん

私の場合、業務ロジック側のみでJTAで、
トランザクションの制御を使っています。

EJBは好きじゃないので使っていませんが、
単一のDBの利用のみでもJTAを使っています。

これは、単純に複数DBを扱うようになったときに、
業務ロジックを修正しなくても済むというのと、
単一のリソースが対象の場合、JTA実装のほとんどが
2フェーズコミットを行わないので、
コストがJDBCのトランザクションと変わらないという点です。
Tol
常連さん
会議室デビュー日: 2004/07/16
投稿数: 27
投稿日時: 2007-01-31 20:57
別にトランザクション管理を業務ロジックに記述してはいけないって
わけではないんですね。

とすると、業務ロジックから直接Connectionクラスのcommitやrollbackを
行ってもよいのでしょうか?
それとも、何らかの別のクラスを作成して、Connectionクラスは隠す
べきなのでしょうか?

今回はJTAを使う予定はないのですが、他のサイトなどを調べると
Connectionクラスを業務ロジックが直接扱うのはだめで、
JTAを使用するのなら業務ロジックからトランザクション管理を行っても
よいかのような記述があるのですが、なぜだか意味がわかりません。

特に単一のコネクションであれば、Connectionクラスからcommitを行うのも、
JTAからcommitを行うのもまったく同じことだとおもうのですが、
やはりJTAみたいにConnectionのラッパークラス?みたいなのを作って
トランザクション管理を行ったほうがよいのでしょうか?


nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2007-01-31 23:07
引用:

lamさんの書き込み (2007-01-31 20:57) より:
特に単一のコネクションであれば、Connectionクラスからcommitを行うのも、
JTAからcommitを行うのもまったく同じことだとおもうのですが、
やはりJTAみたいにConnectionのラッパークラス?みたいなのを作って
トランザクション管理を行ったほうがよいのでしょうか?



極端な話、一切の仕様変更がない条件の下ではガリガリのハードコーディングもOKなんですよ。
どこまでの仕様変更に耐えられるか、という観点で見れば抽象度の高い設計が
よりよいわけですが、何があろうとひっくり返らないという前提の部分に
妙に抽象度の高い設計をしても無駄なんですよね。
そういう意味でケースバイケースで万能解はないと思います。

lam氏のプロジェクトにおいて、そのような設計にしてメリットはなんでしょう?
デメリットはなんでしょう?
大事なのは多数派に倣うことではなく、自分のケースで
その設計が生きるかどうかを考えることだと思います。

もし、ご自分の判断に自信がないとおっしゃるのであれば、
メリットとされるものが自分のケースにおいて生きない理由、
デメリットとされるものが自分のケースにおいて問題とならない理由、
それらを挙げて、自分はこう考えた、この判断の是非はどうか?
と、問われればよいのです。
そうすれば、第三者である我々はそれなりに客観的な指摘ができますよ。

万能解をくださいという要望には応えることはできません。

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