連載
» 2005年06月08日 00時00分 公開

JavaのDBアクセスを極める(5):デザインパターンを利用したDBアクセスの実装 (2/3)

[林田宏介 著, 安間裕 監修,アクセンチュア・テクノロジー・ソリューションズ]

サンプルケースの概要

 今回はWebを利用して商品を購入するECサイトをサンプルケースとして、実際の永続化の解説を行います。サンプルケースのユースケースを図2に示します。

図2 サンプルケースのユースケース 図2 サンプルケースのユースケース

 サンプルケースでは以下の流れで処理を行います(データベースはリレーショナル・データベースを使用)。

  1. ユーザーが任意の条件を指定して商品を検索する
  2. 検索結果より購入したい商品をショッピングカートに登録する
  3. 商品が確定したら発注ボタンを押して発注処理を行う

 この中のショッピングカートに登録されたデータを発注処理する部分に絞って解説します。永続化の対象となるテーブルのリレーションは図3のとおりです。発注処理ではショッピングカート・テーブルに登録されたデータを発注テーブルと発注明細テーブルへ更新します。

図3 発注処理のリレーション関係 図3 発注処理のリレーション関係

レイヤの分離と責任範囲の明確化

 ビジネスロジック・レイヤとデータベースアクセス・レイヤを分離する必要性については、第1回「JavaとDBのデータモデルはナゼすれ違う?」で解説しました。レイヤを分離することで、相手側に自分が持っているデータの保持属性の影響を及ぼさないようにするわけですが、実際に分離を行う場合にはまずレイヤ間でのコミュニケーションを行うためのインターフェイスを明確化する必要があります。具体的には「Facadeパターン」を利用し、レイヤ間インターフェイスとしてFacadeクラスを通して処理を行います。具体的な処理イメージは図4のようになります。

図4 Facadeパターンを利用した処理イメージ  図4 Facadeパターンを利用した処理イメージ

 Facadeパターンを利用した場合、業務クラスからの要求に応じて対象となる各テーブルのDAOインスタンスを生成し処理を実行するのはFacadeクラスです。このとき業務クラス側からは、Facadeに対して発注処理を行いたいといったメッセージ(オブジェクト)を送るのみで、データベース・アクセスはまったく意識する必要はありません。Facadeクラスは業務クラスから受け取ったメッセージを元に永続化対象となるDAOインスタンスを生成し、各DAOクラスに永続化対象となるオブジェクトを受け渡します。このようにFacadeクラスはビジネスロジック側からは処理の窓口として、データベース・アクセス側からは処理を制御されるクラスとして存在します。Facadeパターンを利用することで、業務クラスはビジネスロジックのみに専念し、DAOクラスは要求に応じたデータベース・アクセスロジックのみを行えるようになります。また、FacadeクラスがDAOクラスのインスタンスの生成/実行をコントロールする必要があるため、トランザクション制御の実装はFacadeクラスで行います。

 FacadeクラスにDAOクラスをコントロールさせることで、DAOクラス自体の構成がスマートになり、実装上の問題点として提起した「複雑な永続化処理」とそれに伴う「メンテナビリティの低下」「業務トランザクションの制御の複雑化」を回避することが可能となります。

 それでは実際にサンプルケースの発注処理を基に実装を見てみましょう。Facadeパターンを利用する場合のクラス構成は以下のようになります。

  • PersistenceException:業務クラスへ例外をスローするクラス:業務クラスへ例外をスローするクラス
  • TransactionManager:トランザクションを制御するクラスTransactionManager:トランザクションを制御するクラス
  • OrderFacade:商品購入の窓口となるFacadeクラス:商品購入の窓口となるFacadeクラス

業務クラスへ例外をスローするクラス

 まず、PersistenceException.javaですが、これは単純に業務クラスへ例外をスローするだけのクラスですので特に細かい説明は省略します。

public class PersistenceException extends Exception {
  public PersistenceException (String str) {
    super(str);
  }
}
リスト1 業務クラスへ例外をスローするクラス(PersistenceException.java)

トランザクションを制御するクラス

 次のTransactionManager.javaは、トランザクション制御を行うクラスです。トランザクション・リソースの取得とトランザクションの開始/コミット/ロールバックといった機能を実装しており、Facadeクラスから用途に応じて利用されます。なお、トランザクション制御をDAOクラスではなく上位のFacadeクラスに持たせているため、今回はJTAを利用したトランザクション制御を行っています。

public class TransactionManager {
  private UserTransaction utx = null;
  //トランザクション・リソースの生成
  public TransactionManager() throws PersistenceException {
    try {
      // UserTransactionの取得は環境により異なります
      InitialContext ctx = new InitialContext();
      Object obj = ctx.lookup("Java:comp/UserTransaction"); 
      utx = (UserTransaction)
          PortableRemoteObject.narrow(obj,
                                      UserTransaction.class);
    } catch (NamingException ex) {
      ex.printStackTrace();
      throw new PersistenceException("begin failure:" +
                                     ex.getMessage());
    }
  }
  //開始処理
  public void begin() throws PersistenceException {
    try {
      utx.begin();
    } catch (Exception ex) {
      ex.printStackTrace();
      throw new PersistenceException("begin failure:" +
                                     ex.getMessage());
    }
  }
  //コミット処理
  public void commit() throws PersistenceException {
    try {
      utx.commit();
    } catch (Exception ex) {
      throw new PersistenceException("commit failure:" +
                                     ex.getMessage());
    }
  }
  //ロールバック処理
  public void rollback() throws PersistenceException {
    try {
      utx.rollback();
    } catch (Exception ex) {
      throw new PersistenceException("rollback failure:" +
                                     ex.getMessage());
    }
  }
}
リスト2 トランザクションを制御するクラス(TransactionManager.java)

商品購入の窓口となるFacadeクラス

 最後にメインとなるOrderFacade.javaです。このクラスは業務クラスに対して商品購入という目的を実施するための窓口として実装され、それぞれの処理に応じて必要なDAOインスタンスを生成し、データベースの参照/更新/削除などの処理を呼び出します。また、トランザクションを実装するために、TransactionManagerを利用してトランザクション・リソースの生成/開始などの処理を実行します。

 実際に発注処理を行うOrderメソッドを例に取って見てみましょう。Orderメソッドが呼ばれると、まず発注処理で利用するDAOインスタンスを生成し、同時にデータベース・コネクションもDAOクラス内で生成します(DAOインスタンス生成については後で解説)。次にトランザクション・リソースを生成し、トランザクションを開始して永続化処理を行える状態にします。後はショッピングカートに登録されている情報を取得し、発注テーブルと発注明細テーブルを更新し、発注処理が完了します。途中で処理に不具合があった場合にはロールバック処理を行い、正常に更新が終了した場合にはコミット処理を行い更新を確定させます。最後にDAOクラスのCloseメソッドを呼び、データベース・コネクションのClose処理を行います。ここでのポイントは以下のとおりとなります。

  • データベース・コネクションの生成はDAOクラスで行う
  • トランザクションの制御はFacadeクラスで行う
  • データベース・コネクションのクローズはFacadeで行う(実装自体はDAOクラス)

 Facadeクラスの作成の注意点として、1つのFacadeクラスをすべてのデータベース・アクセスの窓口として使用すると、コードが膨大になりすぎて保守性が著しく悪化します。汎用的な目的を持った単位でFacadeクラスを作成していくようにしましょう。今回のケースでは商品の購入という目的単位でFacadeクラスを作成しています。

public class OrderFacade {
  public OrderFacade() {
  }
  //
  // 中略
  //
  /*
   *  発注処理
   */
  public boolean Order(String cart_id)
        throws PersistenceException {
    //DAOインスタンスの生成
    DAOFactory dao =
          DAOFactory.getDAOFactory(DAOFactory.ORACLE);
    ShoppingcartDAO sdao = dao.getShoppingcartDAO();
    OrderDAO odao = dao.getOrderDAO();
    Order_detailDAO oddao = dao.getOrder_detailDAO();
    //トランザクション・リソースの取得
    TransactionManager tm = new TransactionManager();
    //トランザクションの開始
    try {
      tm.begin();
      //ショッピングカート・データの取得
      ShoppingDTO sdto = sdao.findShoppingCart(cart_id);
      //発注テーブルの更新データのセット
      odao.setUserId(sdto.getUserId());
      //発注テーブルの更新
      odao.insertOrder();
      //発注IDセット
      sdto.setHachuId(odao.getHachuId());
      //発注明細テーブルの更新
      oddao.insertOrder_detail(sdto);
      //コミット処理
      tm.commit();
    } catch (Exception ex) {
      //ロールバック処理
      tm.rollback();
      throw new PersistenceException("Order failure:" +
                                     ex.getMessage());
    } finally {
      //コネクションのクローズ
      sdao.close();
      odao.close();
      oddao.close();
    }
    return true;
  }
}
リスト3 商品購入の窓口となるFacadeクラス(OrderFacade.java)

Point

  • Facadeパターンの適用により、DAOクラスを上位クラスでコントロールできるようになるので、永続化処理の複雑化とそれに伴うメンテナビリティの低下/トランザクション制御の複雑化を回避することが可能となる。
  • Facadeクラスは汎用的な目的単位で作成する。
  • Facadeクラスでトランザクション制御を実装する。
  • データベースコネクションのオープンはDAOクラスで、クローズはFacadeクラスで実装する。

次ページへ続く)

Copyright© 2017 ITmedia, Inc. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。