33

データ アクセス オブジェクト (DAO) は一般的な設計パターンであり、Sun によって推奨されています。しかし、Java DAO の最も初期の例では、リレーショナル データベースと直接対話していました。つまり、それらはオブジェクト リレーショナル マッピング (ORM) を行っていました。最近では、JDO や Hibernate などの成熟した ORM フレームワークの上に DAO があるのを目にしますが、それが本当に良い考えなのか疑問に思います。

JDOを永続層としてWebサービスを開発しており、DAOの導入を検討しています。他のオブジェクトのマップを含む特定のクラスを扱うときに問題が発生することが予想されます。

public class Book {
    // Book description in various languages, indexed by ISO language codes
    private Map<String,BookDescription> descriptions;
}

JDO は、これを "BOOKS" テーブルと "BOOKDESCRIPTIONS" テーブルの間の外部キー制約にマッピングするほど巧妙です。BookDescription オブジェクトを透過的に読み込み (遅延読み込みを使用していると思います)、Book オブジェクトが永続化されるとそれらを永続化します。

「データ アクセス レイヤー」を導入して BookDao のようなクラスを作成し、その中にすべての JDO コードをカプセル化するとしたら、この JDO の子オブジェクトの透過的な読み込みはデータ アクセス レイヤーを迂回するのではないでしょうか? 一貫性を保つために、BookDescriptionDao オブジェクト (または BookDao.loadDescription メソッド) を介してすべての BookDescription オブジェクトをロードして永続化するべきではありませんか? しかし、そのようにリファクタリングすると、モデルの操作が不必要に複雑になります。

私の質問は、ビジネス層で直接 JDO (または Hibernate、または好きな ORM) を呼び出すことの何が問題なのですか? その構文はすでに非常に簡潔であり、データストアに依存しません。それをデータ アクセス オブジェクトにカプセル化する利点は何ですか?

4

10 に答える 10

13

あなたはいくつかのポイントを作ります。それでも私は Dao レイヤーを使用しています。その理由は次のとおりです。

  1. データベース アクセスは、リモート システムへの呼び出しです。そのようなすべてのケース (Web サービス、ajax なども含む) では、対話の粒度は十分に大きくする必要があります。小さな呼び出しが多数あると、パフォーマンスが低下します。このパフォーマンスの必要性は、多くの場合、システムまたはレイヤー (ここでは Dao レイヤー) の異なるビューを必要とします。

  2. 場合によっては、永続化操作がオブジェクトのロード/保存/削除のみになることがあります。1 つの一意の Dao (またはスーパークラス; Generics を検討してください) がこれを担当できるため、これらのメソッドを何度もコーディングする必要はありません。
    しかし、多くの場合、 ORM によって自動的に作成されない特定のリクエストを実行するなど、特定のニーズもあります。そこでは、特定の Dao メソッドを使用して特定のニーズをコーディングします (多くの場合、再利用が可能です)。
    同じレイヤーに定期的かつ特定のニーズがあると、再利用が可能になります (たとえば、傍受により、必要なときにデータベース接続が開かれている/コミットされていることを確認できます)。

于 2009-09-04T10:38:03.803 に答える
10

レイヤーの目標が何であるかによって異なります。抽象化を入れて、別のセットに対して別のセマンティクスのセットを提供します。一般に、将来のメンテナンスの開発などを簡素化するために、さらにレイヤーがあります。しかし、それらには他の用途があるかもしれません。

たとえば、ORM コード上の DAO (または永続化処理) レイヤーは、ビジネス ロジックを汚染したくない特殊な回復およびエラー処理機能を提供します。

于 2009-09-04T10:31:10.573 に答える
6

JDOやJPAなどのORMツールを使用する場合、DAOはアンチパターンです。この場合、「データアクセス層」の作成は完全に不要であり、コードベースに余分なコードと複雑さを追加するだけであり、開発と保守が困難になります。

以前の経験に基づいて、Persistence永続性関連の操作に使いやすい高レベルのAPIを提供するために、たとえば、単純な静的ファサードの使用をお勧めします。

次に、静的インポートを使用して、便利な場所でこれらのメソッドに簡単にアクセスできます。たとえば、次のようなコードを作成できます。


    List<Book> cheapBooks = 
        find("select b from Book where b.price < ?", lowPriceForBooks);
    ...
    Book b = new Book(...);
    persist(b);
    ...
    Book existingBook = load(Book.class, bookId);
    remove(existingBook);
    ...

上記のコードは可能な限り簡単でシンプルであり、簡単に単体テストを行うことができます。

于 2009-09-04T12:09:35.727 に答える
6

一言:取引

1 つのトランザクションで 2 つのデータ更新操作を実行する必要がある状況を考えてみましょう。これらの操作が一緒になって、論理的な作業単位を形成します。私のビジネス ロジックは、その作業単位の観点から自分自身を表現したいと考えており、トランザクションの境界に煩わされることは望んでいません。

だから私はDAOを書きます。Spring トランザクションを使用して次の擬似コードを取得し、休止状態にします。

@Rogerを非常に怒らせていたが、要点とは関係のないHQLを削除するために編集されました

@Transactional
public void doUnitOfWork() {
  // some persistence operation here
  // some other persistence operation here
}

私のビジネス ロジックは doUnitOfWork() を呼び出します。これは、トランザクションを開始し、両方の永続化操作を実行してからコミットします。トランザクション、または実行される操作については認識も気にもしません。

さらに、DAO が doUnitOfWork() メソッドを使用してインターフェイスを実装する場合、ビジネス ロジックをインターフェイスにコーディングできるため、単体テストが容易になります。

通常、私は常にデータ アクセス操作を DAO でラップし、その周りにインターフェイスを配置します。

于 2009-09-04T12:25:39.053 に答える
3

ほとんどのDAOは、歴史的な(歴史的な;])理由で人々によって追加されたと思います。ORM 以前の時代に CRUD 操作を実行するために必要な SQL 接着剤の便利なカプセル化として意図されていたという点で、あなたは正しいです。現在、透過的な持続性により、それらの役割はほとんど不要になっています。

現在適切なのは、リポジトリとサービスの概念です。

リポジトリ: ORM 固有のコード (Hibernate や JDO など) で実装されたクエリ メソッドのコレクションを格納するクラス

通常、抽象基本クラス リポジトリを作成してから、ORM 固有のコードですべてのクエリ メソッドを実装する ORM 固有の実装を提供できます。このアプローチの優れた点は、MockRepository 実装を作成して、DB を使用せずにアプリをテストできることです。

サービス: オブジェクト モデル (通常は ORM に依存しないコード) への重要な変更/追加を調整できるメソッドのコレクションを格納するクラス。

これにより、アプリの大部分を ORM から独立させることができます。アプリを別の ORM に移植するには、新しい ORM 固有のリポジ​​トリ クラスを実装するだけです。

于 2010-11-24T01:53:26.237 に答える
3

「エンティティごとの DAO クラス」というパターンは、ORM で管理されたデータ レイヤーでは絶対に冗長であると思います。代わりに、DAO レイヤーは、任意のエンティティ クラスを操作する汎用 CRUD メソッド セットと、データに対してより高度な操作を実行する多数のメソッドで構成する必要があります。機能が十分に大きい場合は、ドメイン基準に基づいて DAO レイヤーを複数のクラスに分割する必要があります。これにより、このアプローチはサービス指向アーキテクチャにより似たものになります。

于 2011-06-17T07:28:18.050 に答える
0

実際には、これらすべての答えがそうであると判明するよりも簡単でなければなりません. これらのパターンはすべてレイヤーに関するものです。循環参照を作成して、その上にあるものしか認識できないレイヤーを作成したくありません。UICode ですべてのサービスを参照できるようにし、Service コードですべての DAO を参照できるようにします。

  1. ダオ
  2. サービス
  3. UIコード

POJO は上から下に渡されます。

于 2009-09-04T12:18:17.957 に答える