SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

Jakarta Commonsを使ってJDKクラスを拡張する:パート2

Commons Codec/DBCP/DBUtils/Email/i18nの利用

DBCP

 DBCP(Database Connection Pool)コンポーネントは、JDBCリソースをプールする必要のあるアプリケーションで利用できます。このコンポーネントは、JDBC接続とは別にStatementインスタンスとPreparedStatementインスタンスのサポートも提供します。

 JakartaのWebサイトにあるDBCPのドキュメントの説明は包括的で役に立ちます。特にユーザーガイドのDBCP Wikiサイトシーケンス図は一見の価値があります。「org.apache.commons.dbcp」パッケージのjavadocには、APIに関する詳細な情報も含まれています。DBCPを使用するようにTomcatを設定する方法については、Jakarta-commons Wikiを参照してください。

 このセクションのサンプルアプリケーションでは、軽量データベースエンジンHypersonic SQLを使ってDBCPの機能を例示しています。このアプリケーションの主な目的は、名前や電子メールアドレスなどの連絡先情報を格納して取り出すことにあります。このアプリケーションでは、DBCPフレームワークが提供するプリペアードステートメントとプールされたJDBC接続を使用します。ソースファイルはソースコードの「src」フォルダ内のパッケージ「in.co.narayanan.commons.dbcp」に収められています。

 このアプリケーションでは以下のクラスを使用しています。

ContactInfo連絡先の詳細を表現するドメインオブジェクト。
ContactInfoRepositoryデータベースから連絡先レコードを作成するcreateContactInfoメソッドや、連絡先を検索するfindByNameメソッドなどが含まれているDAOクラス(このクラスに、プールされた接続およびステートメントの取得元となるIDatabaseContextの実装クラスへの参照が与えられます)。
DatabaseContextDBCPを使用してプールされた接続とステートメントをDAOクラスに供給します。

 TestDBCP JUnitテストケースクラスを実行してアプリケーションを起動してください(アプリケーションの実行中は「hsqldb.jar」をクラスパスに入れておく必要があります)。このクラスはDatabaseContextを初期化し、ContactInfoRepositoryに参照を渡して、連絡先の詳細を格納します。リスト7はDBCPフレームワークを初期化するためのコードです。

リスト7 DBCPフレームワークを初期化する
// Load the HSQL Database Engine JDBC driver
// hsqldb.jar should be in the class path
try {
    Class.forName("org.hsqldb.jdbcDriver");
} catch (ClassNotFoundException e) {
    throw new DbException("Unable to load the db driver", e);
}

Properties db = getDBProperties();
ConnectionFactory connectionFactory =
        new DriverManagerConnectionFactory(db.getProperty("url"),
                                           db.getProperty("user"),
                                           db.getProperty("password"));

connectionPool = new GenericObjectPool();
KeyedObjectPoolFactory stmtPool =
    new GenericKeyedObjectPoolFactory(null);
new PoolableConnectionFactory(
    connectionFactory,connectionPool,stmtPool,null,false,true);
dataSource = new PoolingDataSource(connectionPool);

 DBCPは接続とステートメント参照をプールするためにCommons Poolフレームワークを使用します。このフレームワークは汎用性があって、任意のオブジェクトをプールできます。PoolableConnectionFactoryクラスはインスタンス化の際にコンストラクタに渡されたGenericObjectPoolインスタンスに自分自身を登録します。このファクトリクラスはJDBC接続の新しいインスタンスを作成するのに使われます。

 接続プール参照をPoolingDataSourceに渡す必要があります。PoolingDataSourceクラスはjavax.sql.DataSourceインターフェイスを実装して、プールされた接続を提供します。DAOクラスはdataSource変数を使用して接続を取得することができます。

 KeyedObjectPoolFactoryクラスのインスタンスをPoolableConnectionFactoryコンストラクタに渡すと、JDBC接続が作成するプリペアードステートメントオブジェクトのインスタンスをプールすることができます。KeyedObjectPoolFactoryはプールファクトリの変形で、リソースがキーごとにプールされます。プリペアードステートメントの場合、クエリがキーとして機能します。したがって、同じクエリの呼び出しに対してプールされたプリペアードステートメントインスタンスが返されます。

 リスト8はDAOクラス内のごく一般的なメソッドです。7~9行目でDatabaseContextから接続を取得し、それを使ってデータベースにレコードを挿入します。

リスト8 プールされた接続とPreparedStatementオブジェクトの使用
String query = "INSERT INTO contactinfo(name,email) VALUES(?,?)";
Connection con = null;

PreparedStatement createContactPrStmt = null;
try {
    try {
        con = context.getConnection();
        createContactPrStmt =
            context.getPreparedStatement(con, query);
        createContactPrStmt.setString(1, contactInfo.getName());
        createContactPrStmt.setString(2, contactInfo.getEmailAddress());
        createContactPrStmt.execute();
    } finally {
        if(createContactPrStmt != null) {
            createContactPrStmt.close();
        }
        if(con != null) {
            con.close();
        }
    }
} catch(SQLException e) {
    throw new DbException("Unable to create ContactInfo record", e);
} catch(DbException e) {
    throw new DbException("Unable to create ContactInfo record", e);
}

 DBCPで使われるプールはカスタマイズ性が高いので、エンタープライズソフトウェアに適しています。

DBUtils

 DBUtilsフレームワークはJDBC APIを使いやすくする軽量ラッパーです。これにより、開発者はデータの照会と更新に専念し、リソースのクリーンアップをフレームワークに任せることができます。

 このコンポーネントはデータアクセスオブジェクトでの使用にうってつけです。持続性のためにHibernateJDOを使用する必要はないが、ダイレクトJDBC呼び出しを必要とするアプリケーションでは、DBUtilsを使用すると開発効率が上がります。Jakartaのサイト内の「Overview」「Examples」は非常に包括的です。このフレームワークに含まれているクラスは多くないので、javadocも読みやすいです。

 DBUtilsはどのような働きをするのでしょうか。SQLクエリのSELECTINSERTDELETE、またはUPDATEQueryRunnerクラスのqueryメソッドに渡すことができます。クエリに加えて、ResultSetHandlerインターフェイスの実装も渡します。SELECTクエリが実行されると、取得したResultSetオブジェクトがハンドラに渡されます。ハンドラはレコードを読み取り、ドメインオブジェクトを作成し、呼び出し元に返すことができます。作成されたドメインオブジェクトはqueryメソッドの呼び出し元に返されます。

 このフレームワークには、ArrayHandlerArrayListHandlerBeanHandlerBeanListHandlerColumnListHandlerKeyedHandlerMapHandlerMapListHandlerScalarHandlerなどのハンドラがあります。しかし、ResultSetHandlerを実装することで、特定の状況に使用する独自のハンドラを書くこともできます。

 以降では、このフレームワークの例を示すために、DBCPフレームワークのサンプルアプリケーションの修正版を紹介します。DatabaseContextクラスとContactInfoRepositoryクラスが、DBUtilsフレームワークを使用するように修正されています。リスト9はこれらの修正のコードです。このコードは、DBCPフレームワークによって返されるDataSourceインスタンスの参照をQueryRunnerコンストラクタに渡します。したがって、クエリーランナーのインスタンスをシステム内のすべてのクラスで利用できます(ソースファイルはソースコードの「src」フォルダ内のパッケージ「in.co.narayanan.commons.dbutils」に収められています)。

リスト9 DBUtilsを使用するためにDatabaseContextクラスに加えられた修正
public class DatabaseContext implements IDatabaseContext {
    // Other declarations
    private QueryRunner qRunner;
 
    public DatabaseContext() throws DbException {
        init();
    }
 
    private void init() throws DbException {
        // Initializing for DBCP
        dataSource = new PoolingDataSource(connectionPool);
        qRunner = new QueryRunner(dataSource);
    }
 
    // Other public and private methods
    public QueryRunner getQueryRunner() {
        return qRunner;
    }
}

 リスト10はContactInfoRepositoryクラスからのコードで、QueryRunnerを使ってデータベースにレコードを挿入する方法を示しています。updateメソッドはSQLクエリとそのパラメータを受け取り、それらをプリペアードステートメントに渡します。ここで注目すべきことは、リソースのクリーンアップをDBUtilsフレームワークがやってくれるので、GUIでユーザーにエラーを表示するためにSQLExceptionだけを処理すればよいという点です。

リスト10 QueryRunnerを使ってレコードを挿入する
public void createContactInfo(ContactInfo contactInfo)
    throws DbException {

    String query = "INSERT INTO contactinfo(name,email) VALUES(?,?)";
    try {
        context.getQueryRunner().update(query,
            new Object[] {contactInfo.getName(),
            contactInfo.getEmailAddress()});
    } catch(SQLException e) {
        throw new DbException(
            "Unable to create ContactInfo record", e);
    }
}

 リスト11では、ResultSetHandlerインターフェイスの実装を作成し、QueryRunner内のqueryメソッドにインスタンスを渡します。データベースからレコードを選択するためにプリペアードステートメントのパラメータも渡します。このリストにはカスタムのResultSetHandlerも含まれており、その使用方法が示されています。より簡単なアプローチは、BeanHandlerを使用し、リフレクションを使ってContactInfoドメインオブジェクトに自動的に値を入れるというものです。

リスト11 QueryRunnerを使ってデータベースからレコードを選択する
private static class ContactInfoRSHandlerByName
    implements ResultSetHandler {

    public Object handle(ResultSet results)
        throws SQLException {
        return getContactInfo(results);
    }

    private ContactInfo getContactInfo(ResultSet results)
        throws SQLException {

        if(results.next()) {
            ContactInfo contact = new ContactInfo();
            contact.setName(results.getString("name"));
            contact.setEmailAddress(results.getString("email"));
            return contact;
        } else {
            return null;
        }
    }
}

public ContactInfo findByName(String name) throws DbException {
    String query = "select name, email from contactinfo where name=?";
    try {
        return (ContactInfo)context.getQueryRunner()
            .query(query,new Object[] {name},
            new ContactInfoRSHandlerByName());
    } catch(SQLException e) {
        throw new DbException(
            "Unable to find ContactInfo record by name", e);
    }
}

次のページ
Email

この記事は参考になりましたか?

japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Narayanan A.R.(Narayanan A.R.)

テスト駆動開発、アジャイル方法論、Javaテクノロジ、およびデザインパターンの熱烈な擁護者。Javaテクノロジを使ったソフトウェアのデザインおよび開発に携わって数年になる。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/284 2006/04/11 19:10

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー