第3章 SessionFactoryの設定

Hibernateは、多くのさまざまな環境で使えるように設計されているので、 設定パラメータがたくさん用意されています。 さいわい、ほとんどのパラメータには適当なデフォルト値が定められており、 またさまざまなオプションを示す hibernate.properties ファイルのサンプルが付属しています。 普通はクラスパスにこのファイルを置いて、カスタマイズするだけで十分のはずです。

3.1. プログラムでの設定

net.sf.hibernate.cfg.Configuration のインスタンスは、 アプリケーションのJava型からリレーショナル・データベースへのマッピングのセットを表します。 Configuration は、 (更新不能の)SessionFactory をビルドするために使います。 マッピングはいろいろなXMLマッピング・ファイルからコンパイルされます。

Configuration インスタンスは、直接インスタンス化して取得できます。 これは(クラスパスにおいて)2つのXML設定ファイルで定義されたマッピングからの データストアの設定例です:

Configuration cfg = new Configuration()
    .addFile("Item.hbm.xml")
    .addFile("Bid.hbm.xml");

もう1つの(ときどきはより良い)方法は、getResourceAsStream() を使って マッピング・ファイルをロードする方法です。

Configuration cfg = new Configuration()
    .addClass(org.hibernate.auction.Item.class)
    .addClass(org.hibernate.auction.Bid.class);

するとHibernateはクラスパスで、 /org/hibernate/autcion/Item.hbm.xml/org/hibernate/autcion/Bid.hbm.xml という名前のマッピング・ファイルを探します。 この方法を使えば、ファイル名をハード・コーディングしなくてすみます。

Configuration でも、いろいろなオプションのプロパティを指定します:

Properties props = new Properties();
...
Configuration cfg = new Configuration()
    .addClass(org.hibernate.auction.Item.class)
    .addClass(org.hibernate.auction.Bid.class)
    .setProperties(props);

Configuration は設定時のオブジェクトとして考えられており、 SessionFactory が作成された後は捨てられるものと意図されています。

3.2. SessionFactoryの取得

すべてのマッピングが Configuration によって構文解析されたとき、 アプリケーションは Session インスタンスのファクトリを 取得しなければなりません。 このファクトリはすべてのアプリケーション・スレッドで共有されるものと考えられています:

SessionFactory sessions = cfg.buildSessionFactory();

しかしHibernateは、アプリケーションが SessionFactory を 複数インスタンス化することを許しています。 これは複数のデータベースをを使うときに役に立ちます。

3.3. ユーザが用意するJDBCコネクション

SessionFactory は、 ユーザが用意したJDBCコネクションで Session をオープンできます。 この設計により、アプリケーションが欲しいときにいつでも、 JDBCコネクションを取得できます:

java.sql.Connection conn = datasource.getConnection();
Session session = sessions.openSession(conn);

// データにアクセスする作業をいくつか行います

アプリケーションは同じJDBCコネクションで、 2つの同時並行 Session をオープンしないように気を付けなければいけません。

3.4. Hibernateが用意するJDBCコネクション

Alternatively, you can have the SessionFactory open connections for you. The SessionFactory must be provided with JDBC connection properties in one of the following ways: もう1つの方法として、SessionFactory にコネクションをオープンさせることもできます。 SessionFactory には以下の方法のどれか1つを使い、 JDBCコネクション・プロパティを与えなければいけません:

  1. java.util.Properties のインスタンスを Configuration.setProperties() に渡す。

  2. hibernate.properties をクラスパスのルート・ディレクトリに置く。

  3. java -Dproperty=value を使い、 System プロパティを設定する。

  4. hibernate.cfg.xml<property> 要素を含める(後で議論します)。

この方法を使えば、以下のように Session のオープンが簡単になります:

Session session = sessions.openSession(); // 新しいSessionをオープンします
// データにアクセスする作業をいくつか行います。JDBCコネクションが要求に応じて使われます。

すべてのHibernateプロパティの名前と意味は、 net.sf.hibernate.cfg.Environment クラスで定義されています。 それでは、JDBCコネクションの最も重要な設定について述べていきます。

以下のプロパティを設定すれば、Hibernateは java.sql.DriverManager を使って、 コネクションを取得(そしてプール)します:

表 3.1. Hibernate JDBC プロパティ

プロパティ名目的
hibernate.connection.driver_classJDBCドライバ・クラス
hibernate.connection.urlJDBC URL
hibernate.connection.usernameデータベースのユーザ
hibernate.connection.passwordデータベースのユーザのパスワード
hibernate.connection.pool_sizeプールするコネクションの最大数

Hibernate独自のコネクション・プーリング・アルゴリズムは、かなり初歩的なものです。 これはHibernateを始める手助けのためのものであり、 製品のシステムでのしようを意図していません し、 パフォーマンス・テストへの使用でさえ意図していません。 最高のパフォーマンスと安定性を得るためには、サードパーティのプールを使ってください。 そしてコネクション・プールの設定で、 hibernate.connection.pool_size プロパティを置き換えてください。

C3P0はオープン・ソースのJDBCコネクション・プールで、Hibernateと一緒に配布されています。 これは lib ディレクトリにあります。 hibernate.c3p0.* プロパティを設定すれば、 Hibernateはコネクション・プールのために、組み込みの C3P0ConnectionProvider を使います。 また、Apache DBCPとProxoolも組み込みでサポートしています。 DBCPConnectionProvider を有効にするには、 hibernate.dbcp.* プロパティ (DBCPコネクション・プール・プロパティ)を設定しなければいけません。 hibernate.dbcp.ps.* (DBCPステートメント・キャッシュ・プロパティ)が設定されれば、 Prepared statementのキャッシュが有効になります(非常におすすめです)。 これらのプロパティについては、Apache commons-poolのドキュメントを参照してください。 またProxoolを使いたければ、hibernate.proxool.* プロパティを設定してください。

以下は、C3P0を使った例です:

hibernate.connection.driver_class = org.postgresql.Driver
hibernate.connection.url = jdbc:postgresql://localhost/mydatabase
hibernate.connection.username = myuser
hibernate.connection.password = secret
hibernate.c3p0.min_size=5
hibernate.c3p0.max_size=20
hibernate.c3p0.timeout=1800
hibernate.c3p0.max_statements=50
hibernate.dialect = net.sf.hibernate.dialect.PostgreSQLDialect

アプリケーション・サーバの内部で使うために、 HibernateはJNDIで登録された javax.sql.Datasource からコネクションを取得できます。 以下のプロパティを設定してください:

表 3.2. Hibernateデータソース・プロパティ

プロパティ名目的
hibernate.connection.datasourceデータソースのJNDI名
hibernate.jndi.urlJNDIプロバイダのURL(オプション)
hibernate.jndi.classInitialContextFactory のクラス(オプション)
hibernate.connection.usernameデータベースのユーザ(オプション)
hibernate.connection.passwordデータベースのユーザのパスワード(オプション)

以下は、JNDIデータソースが提供したアプリケーション・サーバを使った例です:

hibernate.connection.datasource = java:/comp/env/jdbc/MyDB
hibernate.transaction.factory_class = \
    net.sf.hibernate.transaction.JTATransactionFactory
hibernate.transaction.manager_lookup_class = \
    net.sf.hibernate.transaction.JBossTransactionManagerLookup
hibernate.dialect = \
    net.sf.hibernate.dialect.PostgreSQLDialect

JNDIデータソースから取得されたJDBCコネクションは、 アプリケーション・サーバのコンテナ管理トランザクションに自動的に登録されます。

任意のコネクション・プロパティは、 "hibernate.connnection" の後にプロパティ名を続けることで与えられます。 例えば hibernate.connnection.charSet を使い、 charSet を指定できます。

net.sf.hibernate.connection.ConnectionProvider を実装することで、 JDBCコネクションを取得するための独自のプラグイン戦略を定義できます。 また hibernate.connection.provider_class の設定によって、 カスタムの実装を選べます。

3.5. オプションの設定プロパティ

Hibernateの実行時の振る舞いを制御するために使うプロパティが、他にもたくさんあります。 すべてがオプションで、適当なデフォルト値が設定されています。

システム・レベルのプロパティは java -Dproperty=value で設定するか hibernate.properties で定義し、 Configuration に渡される Properties では設定できません。

表 3.3. Hibernate設定プロパティ

プロパティ名目的
hibernate.dialect Hibernate Dialect のクラス名。 プラットフォーム依存の機能を有効にします。

full.classname.of.Dialect

hibernate.default_schema 生成されるSQLにおいて、与えられるスキーマ/テーブルスペースで 非修飾のテーブル名を修飾します。

SCHEMA_NAME

hibernate.session_factory_name 作成された後、SessionFactory がJNDIにおいて 自動的にこの名前にバインドされます。

jndi/composite/name

hibernate.use_outer_join アウター・ジョインによるフェッチを有効にします。推奨されません。 max_fetch_depth を使ってください。

true | false

hibernate.max_fetch_depth 末端が1の関連(one-to-one, many-to-one)に対して、 アウター・ジョインのツリーの「深さ」の最大値を設定します。 0 と指定すると、 デフォルトのアウター・ジョインによるフェッチが無効になります。

おすすめは 0 から 3 の間の値

hibernate.jdbc.fetch_size 0でない値はJDBCのフェッチ・サイズを決定します (Statement.setFetchSize() をコールします)。
hibernate.jdbc.batch_size 0でない値はHibernateによるJDBC2のバッチ更新を有効にします。

おすすめは 5 から 30 の間の値

hibernate.jdbc.batch_versioned_data もしJDBCドライバが executeBatch() から正しい行数を返すなら、 このプロパティを true に設定してください (普通はこのオプションをオンにしても安全です)。 すると自動的にバージョン付けされたデータに対して、 HibernateはバッチのDMLを使います。 デフォルトは false です。

true | false

hibernate.jdbc.use_scrollable_resultset HibernateによるJDBC2スクローラブル・リザルトセットを有効にします。 このプロパティはユーザが用意するJDBCコネクションを使うときにだけ必要で、 そうでなければHibernateはコネクション・メタデータを使います。

true | false

hibernate.jdbc.use_streams_for_binarybinaryserializable 型をJDBCに書き込んだり 読み込んだりするときに、ストリームを使います (システム・レベルのプロパティです)。

true | false

hibernate.jdbc.use_get_generated_keys 挿入の後にネイティブに生成されたキーを復元するための PreparedStatement.getGeneratedKeys() の使用を有効にします。 これはJDBC3+ドライバとJRE1.4+を必要とし、 もしHibernateの識別子ジェネレータに問題が発生するようならfalseに設定してください。 デフォルトではコネクション・メタデータを使いドライバの能力を決定するようにしてください。

true | false

hibernate.cglib.use_reflection_optimizer 実行時リフレクションの代わりのCGLIBの使用を有効にします (システム・レベルのプロパティ) リフレクションはトラブルシューティングのときに役立つことがあります。 オプティマイザをオフにしているときでさえ、 Hibernateには必ずCGLIBが必要なことに注意してください。 このプロパティは hibernate.cfg.xml で設定できません。

true | false

hibernate.jndi.<propertyName>propertyName プロパティを、 JNDI InitialContextFactory に渡します。
hibernate.connection.isolation JDBCトランザクション分離レベルを設定します。 妥当な値を調べるためには java.sql.Connection をチェックしてください。 しかし使用するデータベースが、すべての分離レベルをサポートしているとは限りません。

1, 2, 4, 8

hibernate.connection.<propertyName>propertyName JDBCプロパティを DriverManager.getConnection() に渡します。
hibernate.connection.provider_class カスタム ConnectionProvider のクラス名。

classname.of.ConnectionProvider

hibernate.cache.provider_class カスタム CacheProvider のクラス名。

classname.of.CacheProvider

hibernate.cache.use_minimal_puts 書き込みを最小限にするために、第2レベル・キャッシュの操作を最適化します。 その代わりに、読み込みがより頻繁に発生するようになります (クラスタ・キャッシュに役に立ちます)。

true|false

hibernate.cache.use_query_cache クエリのキャッシュを有効にします。 個々のクエリはまだキャッシャブルに設定されなければなりません。

true|false

hibernate.cache.query_cache_factory カスタム QueryCache インターフェイスのクラス名。 デフォルトは組み込みの StandardQueryCache です。

classname.of.QueryCache

hibernate.cache.region_prefix 第2レベル・キャッシュの領域の名前に使うプリフィックス。

prefix

hibernate.transaction.factory_class Hibernate Transaction APIと一緒に使われる TransactionFactory のクラス名。 (デフォルトでは JDBCTransactionFactory です)。

classname.of.TransactionFactory

jta.UserTransaction アプリケーション・サーバからJTA UserTransaction を取得するために JTATransactionFactory に使われるJNDI名。

jndi/composite/name

hibernate.transaction.manager_lookup_classTransactionManagerLookup のクラス名。 JTA環境において、JVMレベルのキャッシュを有効にするために必要です。

classname.of.TransactionManagerLookup

hibernate.query.substitutions HibernateクエリのトークンからSQLのトークンへのマッピング (例えばトークンは関数やリテラルの名前かもしれません)。

hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC

hibernate.show_sql すべてのSQL文をコンソールに書き出します。

true | false

hibernate.hbm2ddl.autoSessionFactory が作成されるとき、 自動的にスキーマDDLをデータベースにエクスポートします。 create-drop と指定されると、 SessionFactory が明示的にクローズされるときに データベース・スキーマがドロップされます。

update | create | create-drop

3.5.1. SQL方言

hibernate.dialect プロパティには、 使用するデータベースの正しい net.sf.hibernate.dialect.Dialect のサブクラスを、 必ず指定すべきです。 もし native または sequence 主キー生成や (例えば Session.lock()Query.setLockMode() で) 悲観的ロックを使いたいのでなければ、厳密に言うと必須ではありません。 しかし方言を指定すれば、Hibernateは上述したプロパティのいくつかについて、 より適切なデフォルト値を使います。 そうすれば、それらを手作業で設定する手間が省けます。

表 3.4. Hibernate SQL方言 (hibernate.dialect)

RDBMS方言
DB2net.sf.hibernate.dialect.DB2Dialect
DB2 AS/400net.sf.hibernate.dialect.DB2400Dialect
DB2 OS390net.sf.hibernate.dialect.DB2390Dialect
PostgreSQLnet.sf.hibernate.dialect.PostgreSQLDialect
MySQLnet.sf.hibernate.dialect.MySQLDialect
Oracle (any version)net.sf.hibernate.dialect.OracleDialect
Oracle 9/10gnet.sf.hibernate.dialect.Oracle9Dialect
Sybasenet.sf.hibernate.dialect.SybaseDialect
Sybase Anywherenet.sf.hibernate.dialect.SybaseAnywhereDialect
Microsoft SQL Servernet.sf.hibernate.dialect.SQLServerDialect
SAP DBnet.sf.hibernate.dialect.SAPDBDialect
Informixnet.sf.hibernate.dialect.InformixDialect
HypersonicSQLnet.sf.hibernate.dialect.HSQLDialect
Ingresnet.sf.hibernate.dialect.IngresDialect
Progressnet.sf.hibernate.dialect.ProgressDialect
Mckoi SQLnet.sf.hibernate.dialect.MckoiDialect
Interbasenet.sf.hibernate.dialect.InterbaseDialect
Pointbasenet.sf.hibernate.dialect.PointbaseDialect
FrontBasenet.sf.hibernate.dialect.FrontbaseDialect
Firebirdnet.sf.hibernate.dialect.FirebirdDialect

3.5.2. アウター・ジョインによるフェッチ

データベースがANSIやOracleスタイルのアウター・ジョインをサポートしていれば、 (可能な限りデータベース自体に仕事を任せ) データベースとのやりとりの回数を制限する アウター・ジョインによるフェッチ によって、 パフォーマンスを改善できるかもしれません。 アウター・ジョインにより、many-to-one, one-to-many, one-to-one関連で接続されたオブジェクトのグラフを、 SQL SELECT 1つだけで復元できます。

デフォルトではオブジェクトの取得は、リーフ・オブジェクト、 コレクション、プロキシ・オブジェクト、循環が発生するところで終わります。

特定の関連 に対しては、 XMLマッピングで outer-join 属性を設定することで、 フェッチを有効または無効に(そしてデフォルトの振る舞いをオーバーライド)できます。

hibernate.max_fetch_depth プロパティを 0 に設定することで、 アウター・ジョインによるフェッチを グローバルに 無効にできます。 1 以上に設定すると、すべてのone-to-oneとmany-to-one関連に対して、 アウター・ジョインによるフェッチが可能になります。 これらのアウター・ジョインは、デフォルトでは auto に設定されています。 しかし特定の関連それぞれについて明示的に宣言しなければ、 one-to-many関連とコレクションはアウター・ジョインでフェッチされません。 この振る舞いは、Hibernateクエリで実行時にオーバーライドすることもできます。

3.5.3. バイナリ・ストリーム

OracleはJDBCドライバとの間でやりとりされる byte 配列のサイズを制限します。 binaryserializable 型の大きなインスタンスを使いたければ、 hibernate.jdbc.use_streams_for_binary を有効にしてください。 ただし これはJVMレベルの設定だけです

3.5.4. カスタム CacheProvider

インターフェイス net.sf.hibernate.cache.CacheProvider を実装すると、 JVMレベル(またはクラスタ)第2レベル・キャッシュ・システムを統合できます。 hibernate.cache.provider_class を設定すると、 カスタムの実装を選べます。

3.5.5. トランザクション戦略の設定

Hibernate Transaction APIを使いたければ、 プロパティ hibernate.transaction.factory_class を設定して、 Transaction インスタンスのためのファクトリ・クラスを 指定しなければなりません。 Transaction APIは、ベースとなるトランザクション機構を隠蔽し、 管理された環境と管理されていない環境の両方で、Hibernateのコードの実行を可能にします。

標準的な2つの(組み込みの)選択肢があります:

net.sf.hibernate.transaction.JDBCTransactionFactory

データベース(JDBC)トランザクションに委譲します(デフォルト)

net.sf.hibernate.transaction.JTATransactionFactory

JTAに委譲します(既存のトランザクションが実行中なら、 Session はそのコンテキストで動作します。 そうでなければ、新しいトランザクションを開始します。)

独自のトランザクション戦略も定義できます (例えばCORBAトランザクション・サービスのための戦略)。

JTA環境で更新不能のデータのJVMレベル・キャッシュを使いたければ、 これはJ2EEに対して標準化されていないため、 JTA TransactionManager を取得するための戦略を 指定しなければいけません:

表 3.5. JTAトランザクション・マネージャ

トランザクション・ファクトリアプリケーション・サーバ
net.sf.hibernate.transaction.JBossTransactionManagerLookupJBoss
net.sf.hibernate.transaction.WeblogicTransactionManagerLookupWeblogic
net.sf.hibernate.transaction.WebSphereTransactionManagerLookupWebSphere
net.sf.hibernate.transaction.OrionTransactionManagerLookupOrion
net.sf.hibernate.transaction.ResinTransactionManagerLookupResin
net.sf.hibernate.transaction.JOTMTransactionManagerLookupJOTM
net.sf.hibernate.transaction.JOnASTransactionManagerLookupJOnAS
net.sf.hibernate.transaction.JRun4TransactionManagerLookupJRun4
net.sf.hibernate.transaction.BESTransactionManagerLookupBorland ES

3.5.6. JNDIバインドの SessionFactory

JNDIバインドのHibernate SessionFactory は、 ファクトリの検索と新しい Session の検索を単純化できます。

SessionFactory をJNDI名前空間にバインドさせたければ、 プロパティ hibernate.session_factory_name を使い、 名前(例 java:comp/env/hibernate/SessionFactory)を指定します。 このプロパティを設定しなければ、SessionFactory はJNDIにバインドされません。 これはread-onlyのJNDIデフォルト実装の環境において特に役に立ちます。例 Tomcat)

SessionFactory をJNDIにバインドさせるとき、 Hibernateはイニシャル・コンテキストをインスタンス化するために hibernate.jndi.url, hibernate.jndi.class の値を使います。 それらの値が指定されなければ、デフォルトの InitialContext が使われます。

JNDIを使うことにしたなら、JNDIルック・アップを使い、 EJBや他のユーティリティ・クラスは SessionFactory を取得できます。

3.5.7. クエリ言語の置き換え

hibernate.query.substitutions を使い、 新しいHibernateクエリ・トークンを定義することができます。 例えば:

hibernate.query.substitutions true=1, false=0

これはトークン truefalse を 生成されるSQLにおいて整数リテラルに翻訳します。

hibernate.query.substitutions toLowercase=LOWER

これはSQLの LOWER 関数の名前の付け替えを可能にします。

3.6. ロギング

HibernateはApache commons-loggingを使い、いろいろなイベントをログに取ります。

commons-loggingサービスは(クラスパスに log4j.jar を含めれば)Apache Log4jに、 また(JDK1.4かそれ以上で実行させれば)JDK1.4 loggingに直接出力します。 Log4jは http://jakarta.apache.org からダウンロードできます。 Log4jを使うためには、クラスパスに log4j.properties ファイルを配置する必要があります。 例のプロパティ・ファイルはHibernateと一緒に配布され、それは src/ ディレクトリにあります。

Hibernateのログ・メッセージになれることを強くおすすめします。 Hibernateのログは読みにくくならずにできる限り詳細になるように努力されています。 これは必須のトラブルシューティング・デバイスです。 また上で述べたようにSQLロギングを有効にすることを忘れないでください (hibernate.show_sql)。 パフォーマンスの問題を探すときこれが最初のステップとなります。

3.7. NamingStrategy の実装

インターフェイス net.sf.hibernate.cfg.NamingStrategy を使うと データベース・オブジェクトとスキーマ要素のための「命名標準」を指定できます。

Javaの識別子からデータベースの識別子を自動生成することや、 マッピング・ファイルで与えた「論理的な」カラムとテーブル名から 「物理的な」テーブルとカラム名を生成することのためのルールを用意することができます。 この機能は繰り返しの雑音(例えば TBL_ プリフィックス)を取り除き、 マッピング・ドキュメントの冗長さを減らすことに役立ちます。 Hibernateが使うデフォルトの戦略はかなり最小限に近いものです。

マッピングを追加する前に Configuration.setNamingStrategy() をコールすることで 以下のように異なる戦略を指定することができます:

SessionFactory sf = new Configuration()
    .setNamingStrategy(ImprovedNamingStrategy.INSTANCE)
    .addFile("Item.hbm.xml")
    .addFile("Bid.hbm.xml")
    .buildSessionFactory();

net.sf.hibernate.cfg.ImprovedNamingStrategy is a built-in strategy that might be a useful starting point for some applications. net.sf.hibernate.cfg.ImprovedNamingStrategy は組み込みの戦略です。 これはいくつかのアプリケーションにとって有用な開始点となるかもしれません。

3.8. XML設定ファイル

もう1つの方法は hibernate.cfg.xml という名前のファイルで 十分な設定を指定する方法です。 このファイルは hibernate.properties ファイルの代わりとなります。 もし両方のファイルがあれば、プロパティが置き換えられます。

XML設定ファイルはデフォルトで CLASSPATH に配置されることを期待されています。 これが例です:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 2.0//EN"

 "http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd">

<hibernate-configuration>

    <!-- /jndi/nameのようにリストアップされたSessionFactoryインスタンス -->
    <session-factory
        name="java:comp/env/hibernate/SessionFactory">

        <!-- プロパティ -->
        <property name="connection.datasource">my/first/datasource</property>
        <property name="dialect">net.sf.hibernate.dialect.MySQLDialect</property>
        <property name="show_sql">false</property>
        <property name="use_outer_join">true</property>
        <property name="transaction.factory_class">
            net.sf.hibernate.transaction.JTATransactionFactory
        </property>
        <property name="jta.UserTransaction">java:comp/UserTransaction</property>

        <!-- マッピング・ファイル -->
        <mapping resource="org/hibernate/auction/Item.hbm.xml"/>
        <mapping resource="org/hibernate/auction/Bid.hbm.xml"/>

    </session-factory>

</hibernate-configuration>

Hibernateの設定は以下のように簡単になります。

SessionFactory sf = new Configuration().configure().buildSessionFactory();

また以下のようにすると異なるXML設定ファイルを使うことができます。

SessionFactory sf = new Configuration()
    .configure("/my/package/catdb.cfg.xml")
    .buildSessionFactory();