[hibernate-commits] Hibernate SVN: r14131 - core/trunk/documentation/manual/ja-JP/src/main/docbook/content.
hibernate-commits at lists.jboss.org
hibernate-commits at lists.jboss.org
Thu Oct 25 03:54:59 EDT 2007
Author: xhuang at jboss.com
Date: 2007-10-25 03:54:59 -0400 (Thu, 25 Oct 2007)
New Revision: 14131
Modified:
core/trunk/documentation/manual/ja-JP/src/main/docbook/content/architecture.xml
core/trunk/documentation/manual/ja-JP/src/main/docbook/content/basic_mapping.xml
core/trunk/documentation/manual/ja-JP/src/main/docbook/content/batch.xml
core/trunk/documentation/manual/ja-JP/src/main/docbook/content/performance.xml
core/trunk/documentation/manual/ja-JP/src/main/docbook/content/query_hql.xml
core/trunk/documentation/manual/ja-JP/src/main/docbook/content/session_api.xml
core/trunk/documentation/manual/ja-JP/src/main/docbook/content/toolset_guide.xml
core/trunk/documentation/manual/ja-JP/src/main/docbook/content/transactions.xml
core/trunk/documentation/manual/ja-JP/src/main/docbook/content/tutorial.xml
Log:
match to latest English XML
Modified: core/trunk/documentation/manual/ja-JP/src/main/docbook/content/architecture.xml
===================================================================
--- core/trunk/documentation/manual/ja-JP/src/main/docbook/content/architecture.xml 2007-10-25 06:31:49 UTC (rev 14130)
+++ core/trunk/documentation/manual/ja-JP/src/main/docbook/content/architecture.xml 2007-10-25 07:54:59 UTC (rev 14131)
@@ -1,377 +1,377 @@
-<?xml version="1.0" encoding="UTF-8"?>>
+<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<chapter id="architecture">
-
- <title>アーキテクチャ</title>
-
- <sect1 id="architecture-overview" revision="1">
- <title>概観</title>
-
- <para>
- Hibernateアーキテクチャの(非常に)高いレベルからのビュー:
- </para>
-
- <mediaobject>
- <imageobject role="fo">
- <imagedata fileref="../images/overview.svg" format="SVG" align="center"/>
- </imageobject>
- <imageobject role="html">
- <imagedata fileref="../images/overview.png" format="PNG" align="center"/>
- </imageobject>
- </mediaobject>
-
- <para>
- この図はHibernateが、アプリケーションに対して永続化サービス
- (と永続オブジェクト)を提供するために、データベースと設定データを使うことを
- 示しています。
- </para>
-
- <para>
- ここで実行時アーキテクチャのより詳細なビューをお見せしましょう。
- あいにく、Hibernateは柔軟であり、いろいろなアプローチをサポートしています。
- ここでは、2つの極端な例をお見せします。
- 「軽い」アーキテクチャでは、アプリケーションが自前のJDBCコネクションを用意し、
- アプリケーション自身がトランザクションを管理します。
- この方法は、Hibernate APIの最小限のサブセットを使います:
- </para>
-
- <mediaobject>
- <imageobject role="fo">
- <imagedata fileref="../images/lite.svg" format="SVG" align="center"/>
- </imageobject>
- <imageobject role="html">
- <imagedata fileref="../images/lite.png" format="PNG" align="center"/>
- </imageobject>
- </mediaobject>
-
- <para>
- 「重い」アーキテクチャは、アプリケーションから、その下に位置するJDBCやJTAのAPIを
- 取り払って抽象化し、その詳細の面倒をHibernateに見させます。
- </para>
-
- <mediaobject>
- <imageobject role="fo">
- <imagedata fileref="../images/full_cream.svg" format="SVG" align="center"/>
- </imageobject>
- <imageobject role="html">
- <imagedata fileref="../images/full_cream.png" format="PNG" align="center"/>
- </imageobject>
- </mediaobject>
-
- <para>
- 以下は、上の図に含まれるオブジェクトの定義です:
-
- <variablelist spacing="compact">
- <varlistentry>
- <term>SessionFactory (<literal>org.hibernate.SessionFactory</literal>)</term>
- <listitem>
- <para>
- 1つのデータベースに対するコンパイルされたマッピングの
- スレッドセーフな(更新不能の)キャッシュ。
- <literal>Session</literal> のファクトリであり、
- <literal>ConnectionProvider</literal> のクライアント。
- オプションとして、プロセスまたはクラスタレベルにおいて、
- トランザクション間で再利用可能なデータの(二次)キャッシュを持ちます。
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Session (<literal>org.hibernate.Session</literal>)</term>
- <listitem>
- <para>
- アプリケーションと永続ストアとの対話を表す、
- シングルスレッドで短命のオブジェクト。
- JDBCコネクションをラップします。
- <literal>Transaction</literal> のファクトリです。
- 永続オブジェクトの必須の(一次)キャッシュを保持します。
- このキャッシュはオブジェクトグラフをナビゲーションする時や、
- 識別子でオブジェクトを検索する時に使われます。
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Persistent objects と Collections</term>
- <listitem>
- <para>
- 永続化状態とビジネスメソッドを持つ、短命でシングルスレッドのオブジェクト。
- これは通常のJavaBeans/POJOのこともありますが、特徴的なことは、
- その時点での(ただ1つの) <literal>Session</literal> と関連していることです。
- <literal>Session</literal> がクローズされるとすぐに、
- それらは切り離されて他のアプリケーション層から自由に使うことができます。
- (例えばデータ・トランスファ・オブジェクトとして、
- プレゼンテーション層から、またはプレゼンテーション層へ直接使用できます。)
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Transient と detached な objects と Collections</term>
- <listitem>
- <para>
- 現時点では <literal>Session</literal> と関連していない、
- 永続クラスのインスタンス。
- すでにアプリケーション側でインスタンス化されていて、まだ永続化されていないか、
- クローズされた <literal>Session</literal> でインスタンス化されたかのどちらかです。
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Transaction (<literal>org.hibernate.Transaction</literal>)</term>
- <listitem>
- <para>
- (オプション)原子性を持つ作業単位(Unit of Work)を指定するために、アプリケーションが使用する、
- シングルスレッドで短命なオブジェクト。
- 下に位置するJDBC、JTA、CORBAトランザクションからアプリケーションを抽象化します。
- <literal>Session</literal> は、時には
- いくつかの <literal>Transaction</literal> をまたがるかもしれません。
- しかし、下の層のAPIを使うにせよ、 <literal>Transaction</literal> を使うにせよ、
- トランザクション境界を設定することは、決してオプションではありません!。
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>ConnectionProvider (<literal>org.hibernate.connection.ConnectionProvider</literal>)</term>
- <listitem>
- <para>
- (オプション)JDBCコネクション(とそのプール)のファクトリ。
- 下の層に位置する <literal>Datasource</literal> や
- <literal>DriverManager</literal> からアプリケーションを抽象化します。
- アプリケーションには公開されませんが、開発者が継承または実装することは可能です。
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>TransactionFactory (<literal>org.hibernate.TransactionFactory</literal>)</term>
- <listitem>
- <para>
- (オプション) <literal>Transaction</literal> インスタンスのファクトリ。
- アプリケーションには公開されませんが、開発者が継承または実装することは可能です。
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><emphasis>Extension Interfaces</emphasis></term>
- <listitem>
- <para>
- Hibernateは、永続層の振る舞いをカスタマイズするために、
- 多くのオプション拡張インタフェースを用意しています。
- 詳細はAPIドキュメントを参照してください。
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </para>
-
- <para>
- 「軽い」アーキテクチャでは、アプリケーションは直接JTAやJDBCと対話するために、
- <literal>Transaction</literal> や <literal>TransactionFactory</literal> や
- <literal>ConnectionProvider</literal> をバイパスします。
- </para>
- </sect1>
-
- <sect1 id="architecture-states" revision="1">
- <title>インスタンスの状態</title>
- <para>
- 永続クラスのインスタンスは、次の3つの異なる状態のどれかになります。
- それは、 <emphasis>永続コンテキスト</emphasis> によって決まります。
- Hibernateの <literal>Session</literal> オブジェクトが、永続コンテキストになります。
- </para>
-
- <variablelist spacing="compact">
- <varlistentry>
- <term>transient</term>
- <listitem>
- <para>
- この状態のインスタンスは、現在もそして過去においても、
- 永続コンテキストに関連づいていません。また、永続ID(主キーの値)を
- 持っていません。
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>persistent</term>
- <listitem>
- <para>
- この状態のインスタンスは、その時点で永続コンテキストに関連づいています。
- また、永続ID(主キーの値)を持ち、
- たいていはデータベースに対応する行を持っているでしょう。
- 個々の永続コンテキストのなかでは、永続IDが
- JavaのID(オブジェクトのメモリ上の位置)と同じであることを
- Hibernateが <emphasis>保証</emphasis> します。
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>detached</term>
- <listitem>
- <para>
- この状態のインスタンスは、かつて永続コンテキストに関連づけられたが、
- そのコンテキストがクローズされたか、あるいは、
- 他のプロセスにそのインスタンスがシリアライズされたかです。
- このインスタンスは、永続IDを持ち、たいていはデータベースに
- 対応する行を持っているでしょう。分離インスタンスに対しては、
- 永続IDとJavaのIDとの関連は、Hibernateが保証しません。
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </sect1>
-
- <sect1 id="architecture-jmx" revision="1">
- <title>JMXとの統合</title>
-
- <para>
- JMXはJavaコンポーネント管理のJ2EE標準です。
- JMX標準サービスを通して、Hibernateは管理されます。
- ディストリビューションの中に <literal>org.hibernate.jmx.HibernateService</literal> という
- MBean実装を用意しています。
- </para>
-
- <para>
- JBoss アプリケーションサーバー上にHibernateをJMXサービスとしてデプロイする方法の例としては、
- JBoss ユーザガイドを参照してください。 JBoss アプリケーションサーバーにおいて、
- JMXを使ってデプロイすると、次のメリットが得られます。
- </para>
-
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>セッション管理:</emphasis> Hibernateの <literal>Session</literal> のライフサイクルは、
- 自動的にJTAトランザクションのスコープに結びつけられます。これは、もはや手動で
- <literal>Session</literal> をオープンしたり、クローズしたりする必要がないことを意味します。
- これは、JBoss EJB インターセプタの仕事になります。
- また、コードのどこでトランザクション境界を設定するかについて、
- もはや悩む必要がありません(もちろん移植可能な永続層を書かかなくていいのならば、
- オプションのHibernateの <literal>Transaction</literal> を使用してください。)
- <literal>Session</literal> にアクセスするためには、 <literal>HibernateContext</literal> を
- コールしてください。
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>HAR デプロイ:</emphasis> 通常、(EAR または SAR ファイルにある)JBoss サービス
- デプロイメントディスクリプタを使って、Hibernate JMX サービスをデプロイします。
- それは、Hibernateの <literal>SessionFactory</literal> の全ての一般的な設定オプションを
- サポートします。しかし依然としてデプロイメントディスクリプタのなかにすべてのマッピングファイルの
- 名前を挙げる必要があります。
- もし、オプションのHARデプロイメントを使うことを決めたなら、
- JBossは自動的にHARファイルのなかの全てのマッピングファイルを検出します。
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- これらのオプションについての詳細な情報は、JBossアプリケーションサーバユーザガイドを
- 参考にしてください。
- </para>
-
- <para>
- JMXサービスとして利用可能な他の機能に、Hibernate実行時統計情報があります。
- <xref linkend="configuration-optional-statistics"/> を見てください。
- </para>
- </sect1>
-
- <sect1 id="architecture-jca" revision="1">
- <title>JCA サポート</title>
- <para>
- Hibernate は JCA コネクタとしても設定できます。詳細については、Webサイトを見てください。
- Hibernate JCA サポートは、今のところ実験段階として考えられていることに注意してください。
- </para>
- </sect1>
-
- <sect1 id="architecture-current-session" revision="2">
- <title>コンテキスト上のセッション</title>
- <para>
- Hibernate を使ったアプリケーションは、ほとんど、なんらかの形で"コンテキスト上の"セッションが必要になります。
- 「コンテキスト上のセッション」は、特定のコンテキストのスコープのなかで有効なセッションのことです。
- しかし、通常アプリケーションごとにコンテキストを構成するものの定義は異なります。
- しかも、異なる複数のコンテキストは、現時点に対して異なるスコープを定義します。
- バージョン3.0より前の Hibernate では、自作の <literal>ThreadLocal</literal> ベースの「コンテキスト上のセッション」を
- 利用するか、 <literal>HibernateUtil</literal> のようなヘルパークラスを利用するか、
- proxy/interception ベースの「コンテキスト上のセッション」を提供する
- (Spring や Pico のような)サードパーティのフレームワークを利用するかのいずれかでした。
- </para>
-
- <para>
- バージョン 3.0.1 から、Hibernate には <literal>SessionFactory.getCurrentSession()</literal> が
- 加わりました。 これは、 <literal>JTA</literal> トランザクションの使用を前提にしています。
- <literal>JTA</literal> トランザクションは、現在のセッションのスコープとコンテキストの両方を定義します。
- Hibernate チームは、次のことを主張します。
- 巨大なスタンドアロンの <literal>JTA TransactionManager</literal> 実装が成熟したら、
- <literal>J2EE</literal> コンテナ上にデプロイされるかどうかにかかわらず、
- ほとんどの(すべてとは言わないが)アプリケーションが、
- <literal>JTA</literal> トランザクション管理を使用すべきであると。
- この考えに基づくと、 <literal>JTA</literal> ベースの「コンテキスト上のセッション」を
- 使うしかないでしょう。
- </para>
-
- <para>
- しかし、バージョン 3.1 からは、 <literal>SessionFactory.getCurrentSession()</literal> の後の処理が、
- プラガブルになりました。
- これを受けて、現在のセッションを定義するスコープとコンテキストのプラガビリティを可能にするために、
- 新しい拡張インタフェース ( <literal>org.hibernate.context.CurrentSessionContext</literal> ) と
- 新しい構成パラメータ ( <literal>hibernate.current_session_context_class</literal> ) が追加されました。
- </para>
-
- <para>
- <literal>org.hibernate.context.CurrentSessionContext</literal> インタフェースの規約についての
- 詳細な内容は Javadoc を参照してください。
- それには、 <literal>currentSession()</literal> という1つのメソッドが定義されており、
- その実装は、現在の「コンテキスト上のセッション」を追跡することに責任を持ちます。
- そのまま使えるように、Hibernateはこのインタフェースの実装を2つ提供しています。
- </para>
-
- <itemizedlist>
- <listitem>
- <para>
- <literal>org.hibernate.context.JTASessionContext</literal> -
- <literal>JTA</literal> トランザクションによって、現在のセッションが追跡され、
- スコープを決められます。この処理は、古いJTAだけのアプローチとまったく同じです。
- 詳細はJavadocを参照してください。
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>org.hibernate.context.ThreadLocalSessionContext</literal> -
- スレッドの実行によって、現在のセッションが追跡されます。
- 詳細はJavadocを参照してください。
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>org.hibernate.context.ManagedSessionContext</literal> -
- スレッドの実行によって、現在のセッションが追跡されます。
- しかし、このクラスのstaticメソッドで <literal>Session</literal> インスタンスを
- バインド/アンバインドする責任はあなたにあります。
- これは決して <literal>Session</literal> をオープン、フラッシュ、クローズしません。
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- 始めの2つの実装は、"1セッション - 1データベーストランザクション" プログラミングモデルを提供します。
- これは <emphasis>リクエストごとのセッション(session-per-request)</emphasis> としても知られており、使われています。
- Hibernate セッションの開始と終了は、データベーストランザクションの期間で決まります。
- JTAを使わない普通のJSEで、プログラム上のトランザクション境界設定を行うなら、
- コードから基礎のトランザクションシステムを隠蔽するために、
- Hibernate <literal>Transaction</literal> APIを使うとよいでしょう。
- JTAを使うなら、トランザクションの境界設定には、JTAインターフェイスを使ってください。
- CMTをサポートするEJBコンテナで実行するつもりなら、トランザクション境界は宣言的に定義できるため、
- コード上でトランザクションやセッションの境界を設定する必要はありません。
- さらに詳細な情報やコードの例は、 <xref linkend="transactions"/> を参照してください。
- </para>
-
- <para>
- <literal>hibernate.current_session_context_class</literal> 設定パラメータは、
- <literal>org.hibernate.context.CurrentSessionContext</literal> のどの実装を使うかを指定します。
- 下位互換性のため、このパラメータが設定されず
- <literal>org.hibernate.transaction.TransactionManagerLookup</literal> が設定されていた場合、
- Hibernateは <literal>org.hibernate.context.JTASessionContext</literal> を使うことに注意してください。
- 通常このパラメータの値には、3つの実装の中から使用する実装クラスの名前を直接指定します。
- しかし、"jta", "thread", "managed"というそれぞれの省略名も用意されています。
- </para>
-
- </sect1>
-
-</chapter>
-
+
+<chapter id="architecture">
+
+ <title>アーキテクチャ</title>
+
+ <sect1 id="architecture-overview" revision="1">
+ <title>概観</title>
+
+ <para>
+ Hibernateアーキテクチャの(非常に)高いレベルからのビュー:
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="../images/overview.svg" format="SVG" align="center"/>
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="../images/overview.png" format="PNG" align="center"/>
+ </imageobject>
+ </mediaobject>
+
+ <para>
+ この図はHibernateが、アプリケーションに対して永続化サービス
+ (と永続オブジェクト)を提供するために、データベースと設定データを使うことを
+ 示しています。
+ </para>
+
+ <para>
+ ここで実行時アーキテクチャのより詳細なビューをお見せしましょう。
+ あいにく、Hibernateは柔軟であり、いろいろなアプローチをサポートしています。
+ ここでは、2つの極端な例をお見せします。
+ 「軽い」アーキテクチャでは、アプリケーションが自前のJDBCコネクションを用意し、
+ アプリケーション自身がトランザクションを管理します。
+ この方法は、Hibernate APIの最小限のサブセットを使います:
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="../images/lite.svg" format="SVG" align="center"/>
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="../images/lite.png" format="PNG" align="center"/>
+ </imageobject>
+ </mediaobject>
+
+ <para>
+ 「重い」アーキテクチャは、アプリケーションから、その下に位置するJDBCやJTAのAPIを
+ 取り払って抽象化し、その詳細の面倒をHibernateに見させます。
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="../images/full_cream.svg" format="SVG" align="center"/>
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="../images/full_cream.png" format="PNG" align="center"/>
+ </imageobject>
+ </mediaobject>
+
+ <para>
+ 以下は、上の図に含まれるオブジェクトの定義です:
+
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term>SessionFactory (<literal>org.hibernate.SessionFactory</literal>)</term>
+ <listitem>
+ <para>
+ 1つのデータベースに対するコンパイルされたマッピングの
+ スレッドセーフな(更新不能の)キャッシュ。
+ <literal>Session</literal> のファクトリであり、
+ <literal>ConnectionProvider</literal> のクライアント。
+ オプションとして、プロセスまたはクラスタレベルにおいて、
+ トランザクション間で再利用可能なデータの(二次)キャッシュを持ちます。
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Session (<literal>org.hibernate.Session</literal>)</term>
+ <listitem>
+ <para>
+ アプリケーションと永続ストアとの対話を表す、
+ シングルスレッドで短命のオブジェクト。
+ JDBCコネクションをラップします。
+ <literal>Transaction</literal> のファクトリです。
+ 永続オブジェクトの必須の(一次)キャッシュを保持します。
+ このキャッシュはオブジェクトグラフをナビゲーションする時や、
+ 識別子でオブジェクトを検索する時に使われます。
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Persistent objects と Collections</term>
+ <listitem>
+ <para>
+ 永続化状態とビジネスメソッドを持つ、短命でシングルスレッドのオブジェクト。
+ これは通常のJavaBeans/POJOのこともありますが、特徴的なことは、
+ その時点での(ただ1つの) <literal>Session</literal> と関連していることです。
+ <literal>Session</literal> がクローズされるとすぐに、
+ それらは切り離されて他のアプリケーション層から自由に使うことができます。
+ (例えばデータ・トランスファ・オブジェクトとして、
+ プレゼンテーション層から、またはプレゼンテーション層へ直接使用できます。)
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Transient と detached な objects と Collections</term>
+ <listitem>
+ <para>
+ 現時点では <literal>Session</literal> と関連していない、
+ 永続クラスのインスタンス。
+ すでにアプリケーション側でインスタンス化されていて、まだ永続化されていないか、
+ クローズされた <literal>Session</literal> でインスタンス化されたかのどちらかです。
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Transaction (<literal>org.hibernate.Transaction</literal>)</term>
+ <listitem>
+ <para>
+ (オプション)原子性を持つ作業単位(Unit of Work)を指定するために、アプリケーションが使用する、
+ シングルスレッドで短命なオブジェクト。
+ 下に位置するJDBC、JTA、CORBAトランザクションからアプリケーションを抽象化します。
+ <literal>Session</literal> は、時には
+ いくつかの <literal>Transaction</literal> をまたがるかもしれません。
+ しかし、下の層のAPIを使うにせよ、 <literal>Transaction</literal> を使うにせよ、
+ トランザクション境界を設定することは、決してオプションではありません!。
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>ConnectionProvider (<literal>org.hibernate.connection.ConnectionProvider</literal>)</term>
+ <listitem>
+ <para>
+ (オプション)JDBCコネクション(とそのプール)のファクトリ。
+ 下の層に位置する <literal>Datasource</literal> や
+ <literal>DriverManager</literal> からアプリケーションを抽象化します。
+ アプリケーションには公開されませんが、開発者が継承または実装することは可能です。
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>TransactionFactory (<literal>org.hibernate.TransactionFactory</literal>)</term>
+ <listitem>
+ <para>
+ (オプション) <literal>Transaction</literal> インスタンスのファクトリ。
+ アプリケーションには公開されませんが、開発者が継承または実装することは可能です。
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><emphasis>Extension Interfaces</emphasis></term>
+ <listitem>
+ <para>
+ Hibernateは、永続層の振る舞いをカスタマイズするために、
+ 多くのオプション拡張インタフェースを用意しています。
+ 詳細はAPIドキュメントを参照してください。
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+
+ <para>
+ 「軽い」アーキテクチャでは、アプリケーションは直接JTAやJDBCと対話するために、
+ <literal>Transaction</literal> や <literal>TransactionFactory</literal> や
+ <literal>ConnectionProvider</literal> をバイパスします。
+ </para>
+ </sect1>
+
+ <sect1 id="architecture-states" revision="1">
+ <title>インスタンスの状態</title>
+ <para>
+ 永続クラスのインスタンスは、次の3つの異なる状態のどれかになります。
+ それは、 <emphasis>永続コンテキスト</emphasis> によって決まります。
+ Hibernateの <literal>Session</literal> オブジェクトが、永続コンテキストになります。
+ </para>
+
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term>transient</term>
+ <listitem>
+ <para>
+ この状態のインスタンスは、現在もそして過去においても、
+ 永続コンテキストに関連づいていません。また、永続ID(主キーの値)を
+ 持っていません。
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>persistent</term>
+ <listitem>
+ <para>
+ この状態のインスタンスは、その時点で永続コンテキストに関連づいています。
+ また、永続ID(主キーの値)を持ち、
+ たいていはデータベースに対応する行を持っているでしょう。
+ 個々の永続コンテキストのなかでは、永続IDが
+ JavaのID(オブジェクトのメモリ上の位置)と同じであることを
+ Hibernateが <emphasis>保証</emphasis> します。
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>detached</term>
+ <listitem>
+ <para>
+ この状態のインスタンスは、かつて永続コンテキストに関連づけられたが、
+ そのコンテキストがクローズされたか、あるいは、
+ 他のプロセスにそのインスタンスがシリアライズされたかです。
+ このインスタンスは、永続IDを持ち、たいていはデータベースに
+ 対応する行を持っているでしょう。分離インスタンスに対しては、
+ 永続IDとJavaのIDとの関連は、Hibernateが保証しません。
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect1>
+
+ <sect1 id="architecture-jmx" revision="1">
+ <title>JMXとの統合</title>
+
+ <para>
+ JMXはJavaコンポーネント管理のJ2EE標準です。
+ JMX標準サービスを通して、Hibernateは管理されます。
+ ディストリビューションの中に <literal>org.hibernate.jmx.HibernateService</literal> という
+ MBean実装を用意しています。
+ </para>
+
+ <para>
+ JBoss アプリケーションサーバー上にHibernateをJMXサービスとしてデプロイする方法の例としては、
+ JBoss ユーザガイドを参照してください。 JBoss アプリケーションサーバーにおいて、
+ JMXを使ってデプロイすると、次のメリットが得られます。
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>セッション管理:</emphasis> Hibernateの <literal>Session</literal> のライフサイクルは、
+ 自動的にJTAトランザクションのスコープに結びつけられます。これは、もはや手動で
+ <literal>Session</literal> をオープンしたり、クローズしたりする必要がないことを意味します。
+ これは、JBoss EJB インターセプタの仕事になります。
+ また、コードのどこでトランザクション境界を設定するかについて、
+ もはや悩む必要がありません(もちろん移植可能な永続層を書かかなくていいのならば、
+ オプションのHibernateの <literal>Transaction</literal> を使用してください。)
+ <literal>Session</literal> にアクセスするためには、 <literal>HibernateContext</literal> を
+ コールしてください。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>HAR デプロイ:</emphasis> 通常、(EAR または SAR ファイルにある)JBoss サービス
+ デプロイメントディスクリプタを使って、Hibernate JMX サービスをデプロイします。
+ それは、Hibernateの <literal>SessionFactory</literal> の全ての一般的な設定オプションを
+ サポートします。しかし依然としてデプロイメントディスクリプタのなかにすべてのマッピングファイルの
+ 名前を挙げる必要があります。
+ もし、オプションのHARデプロイメントを使うことを決めたなら、
+ JBossは自動的にHARファイルのなかの全てのマッピングファイルを検出します。
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ これらのオプションについての詳細な情報は、JBossアプリケーションサーバユーザガイドを
+ 参考にしてください。
+ </para>
+
+ <para>
+ JMXサービスとして利用可能な他の機能に、Hibernate実行時統計情報があります。
+ <xref linkend="configuration-optional-statistics"/> を見てください。
+ </para>
+ </sect1>
+
+ <sect1 id="architecture-jca" revision="1">
+ <title>JCA サポート</title>
+ <para>
+ Hibernate は JCA コネクタとしても設定できます。詳細については、Webサイトを見てください。
+ Hibernate JCA サポートは、今のところ実験段階として考えられていることに注意してください。
+ </para>
+ </sect1>
+
+ <sect1 id="architecture-current-session" revision="2">
+ <title>コンテキスト上のセッション</title>
+ <para>
+ Hibernate を使ったアプリケーションは、ほとんど、なんらかの形で"コンテキスト上の"セッションが必要になります。
+ 「コンテキスト上のセッション」は、特定のコンテキストのスコープのなかで有効なセッションのことです。
+ しかし、通常アプリケーションごとにコンテキストを構成するものの定義は異なります。
+ しかも、異なる複数のコンテキストは、現時点に対して異なるスコープを定義します。
+ バージョン3.0より前の Hibernate では、自作の <literal>ThreadLocal</literal> ベースの「コンテキスト上のセッション」を
+ 利用するか、 <literal>HibernateUtil</literal> のようなヘルパークラスを利用するか、
+ proxy/interception ベースの「コンテキスト上のセッション」を提供する
+ (Spring や Pico のような)サードパーティのフレームワークを利用するかのいずれかでした。
+ </para>
+
+ <para>
+ バージョン 3.0.1 から、Hibernate には <literal>SessionFactory.getCurrentSession()</literal> が
+ 加わりました。 これは、 <literal>JTA</literal> トランザクションの使用を前提にしています。
+ <literal>JTA</literal> トランザクションは、現在のセッションのスコープとコンテキストの両方を定義します。
+ Hibernate チームは、次のことを主張します。
+ 巨大なスタンドアロンの <literal>JTA TransactionManager</literal> 実装が成熟したら、
+ <literal>J2EE</literal> コンテナ上にデプロイされるかどうかにかかわらず、
+ ほとんどの(すべてとは言わないが)アプリケーションが、
+ <literal>JTA</literal> トランザクション管理を使用すべきであると。
+ この考えに基づくと、 <literal>JTA</literal> ベースの「コンテキスト上のセッション」を
+ 使うしかないでしょう。
+ </para>
+
+ <para>
+ しかし、バージョン 3.1 からは、 <literal>SessionFactory.getCurrentSession()</literal> の後の処理が、
+ プラガブルになりました。
+ これを受けて、現在のセッションを定義するスコープとコンテキストのプラガビリティを可能にするために、
+ 新しい拡張インタフェース ( <literal>org.hibernate.context.CurrentSessionContext</literal> ) と
+ 新しい構成パラメータ ( <literal>hibernate.current_session_context_class</literal> ) が追加されました。
+ </para>
+
+ <para>
+ <literal>org.hibernate.context.CurrentSessionContext</literal> インタフェースの規約についての
+ 詳細な内容は Javadoc を参照してください。
+ それには、 <literal>currentSession()</literal> という1つのメソッドが定義されており、
+ その実装は、現在の「コンテキスト上のセッション」を追跡することに責任を持ちます。
+ そのまま使えるように、Hibernateはこのインタフェースの実装を2つ提供しています。
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>org.hibernate.context.JTASessionContext</literal> -
+ <literal>JTA</literal> トランザクションによって、現在のセッションが追跡され、
+ スコープを決められます。この処理は、古いJTAだけのアプローチとまったく同じです。
+ 詳細はJavadocを参照してください。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>org.hibernate.context.ThreadLocalSessionContext</literal> -
+ スレッドの実行によって、現在のセッションが追跡されます。
+ 詳細はJavadocを参照してください。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>org.hibernate.context.ManagedSessionContext</literal> -
+ スレッドの実行によって、現在のセッションが追跡されます。
+ しかし、このクラスのstaticメソッドで <literal>Session</literal> インスタンスを
+ バインド/アンバインドする責任はあなたにあります。
+ これは決して <literal>Session</literal> をオープン、フラッシュ、クローズしません。
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ 始めの2つの実装は、"1セッション - 1データベーストランザクション" プログラミングモデルを提供します。
+ これは <emphasis>リクエストごとのセッション(session-per-request)</emphasis> としても知られており、使われています。
+ Hibernate セッションの開始と終了は、データベーストランザクションの期間で決まります。
+ JTAを使わない普通のJSEで、プログラム上のトランザクション境界設定を行うなら、
+ コードから基礎のトランザクションシステムを隠蔽するために、
+ Hibernate <literal>Transaction</literal> APIを使うとよいでしょう。
+ JTAを使うなら、トランザクションの境界設定には、JTAインターフェイスを使ってください。
+ CMTをサポートするEJBコンテナで実行するつもりなら、トランザクション境界は宣言的に定義できるため、
+ コード上でトランザクションやセッションの境界を設定する必要はありません。
+ さらに詳細な情報やコードの例は、 <xref linkend="transactions"/> を参照してください。
+ </para>
+
+ <para>
+ <literal>hibernate.current_session_context_class</literal> 設定パラメータは、
+ <literal>org.hibernate.context.CurrentSessionContext</literal> のどの実装を使うかを指定します。
+ 下位互換性のため、このパラメータが設定されず
+ <literal>org.hibernate.transaction.TransactionManagerLookup</literal> が設定されていた場合、
+ Hibernateは <literal>org.hibernate.context.JTASessionContext</literal> を使うことに注意してください。
+ 通常このパラメータの値には、3つの実装の中から使用する実装クラスの名前を直接指定します。
+ しかし、"jta", "thread", "managed"というそれぞれの省略名も用意されています。
+ </para>
+
+ </sect1>
+
+</chapter>
+
Modified: core/trunk/documentation/manual/ja-JP/src/main/docbook/content/basic_mapping.xml
===================================================================
--- core/trunk/documentation/manual/ja-JP/src/main/docbook/content/basic_mapping.xml 2007-10-25 06:31:49 UTC (rev 14130)
+++ core/trunk/documentation/manual/ja-JP/src/main/docbook/content/basic_mapping.xml 2007-10-25 07:54:59 UTC (rev 14131)
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="mapping">
<title>基本的なO/Rマッピング</title>
@@ -801,6 +801,20 @@
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><literal>sequence-identity</literal></term>
+ <listitem>
+ <para>
+ a specialized sequence generation strategy which utilizes a
+ database sequence for the actual value generation, but combines
+ this with JDBC3 getGeneratedKeys to actually return the generated
+ identifier value as part of the insert statement execution. This
+ strategy is only known to be supported on Oracle 10g drivers
+ targetted for JDK 1.4. Note comments on these insert statements
+ are disabled due to a bug in the Oracle drivers.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</para>
@@ -918,6 +932,173 @@
</sect3>
</sect2>
+
+ <sect2 id="mapping-declaration-id-enhanced">
+ <title>Enhanced identifier generators</title>
+
+ <para>
+ Starting with release 3.2.3, there are 2 new generators which represent a re-thinking of 2 different
+ aspects of identifier generation. The first aspect is database portability; the second is optimization
+ (not having to query the database for every request for a new identifier value). These two new
+ generators are intended to take the place of some of the named generators described above (starting
+ in 3.3.x); however, they are included in the current releases and can be referenced by FQN.
+ </para>
+
+ <para>
+ The first of these new generators is <literal>org.hibernate.id.enhanced.SequenceStyleGenerator</literal>
+ which is intended firstly as a replacement for the <literal>sequence</literal> generator and secondly as
+ a better portability generator than <literal>native</literal> (because <literal>native</literal>
+ (generally) chooses between <literal>identity</literal> and <literal>sequence</literal> which have
+ largely different semantics which can cause subtle isssues in applications eyeing portability).
+ <literal>org.hibernate.id.enhanced.SequenceStyleGenerator</literal> however achieves portability in
+ a different manner. It chooses between using a table or a sequence in the database to store its
+ incrementing values depending on the capabilities of the dialect being used. The difference between this
+ and <literal>native</literal> is that table-based and sequence-based storage have the same exact
+ semantic (in fact sequences are exactly what Hibernate tries to emmulate with its table-based
+ generators). This generator has a number of configuration parameters:
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>sequence_name</literal> (optional, defaults to <literal>hibernate_sequence</literal>):
+ The name of the sequence (or table) to be used.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>initial_value</literal> (optional, defaults to <literal>1</literal>): The initial
+ value to be retrieved from the sequence/table. In sequence creation terms, this is analogous
+ to the clause typical named "STARTS WITH".
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>increment_size</literal> (optional, defaults to <literal>1</literal>): The value by
+ which subsequent calls to the sequence/table should differ. In sequence creation terms, this
+ is analogous to the clause typical named "INCREMENT BY".
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>force_table_use</literal> (optional, defaults to <literal>false</literal>): Should
+ we force the use of a table as the backing structure even though the dialect might support
+ sequence?
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>value_column</literal> (optional, defaults to <literal>next_val</literal>): Only
+ relevant for table structures! The name of the column on the table which is used to
+ hold the value.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>optimizer</literal> (optional, defaults to <literal>none</literal>):
+ See <xref linkend="mapping-declaration-id-enhanced-optimizers"/>
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ The second of these new generators is <literal>org.hibernate.id.enhanced.TableGenerator</literal> which
+ is intended firstly as a replacement for the <literal>table</literal> generator (although it actually
+ functions much more like <literal>org.hibernate.id.MultipleHiLoPerTableGenerator</literal>) and secondly
+ as a re-implementation of <literal>org.hibernate.id.MultipleHiLoPerTableGenerator</literal> utilizing the
+ notion of pluggable optimiziers. Essentially this generator defines a table capable of holding
+ a number of different increment values simultaneously by using multiple distinctly keyed rows. This
+ generator has a number of configuration parameters:
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>table_name</literal> (optional, defaults to <literal>hibernate_sequences</literal>):
+ The name of the table to be used.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>value_column_name</literal> (optional, defaults to <literal>next_val</literal>):
+ The name of the column on the table which is used to hold the value.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>segment_column_name</literal> (optional, defaults to <literal>sequence_name</literal>):
+ The name of the column on the table which is used to hold the "segement key". This is the
+ value which distinctly identifies which increment value to use.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>segment_value</literal> (optional, defaults to <literal>default</literal>):
+ The "segment key" value for the segment from which we want to pull increment values for
+ this generator.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>segment_value_length</literal> (optional, defaults to <literal>255</literal>):
+ Used for schema generation; the column size to create this segment key column.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>initial_value</literal> (optional, defaults to <literal>1</literal>):
+ The initial value to be retrieved from the table.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>increment_size</literal> (optional, defaults to <literal>1</literal>):
+ The value by which subsequent calls to the table should differ.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>optimizer</literal> (optional, defaults to <literal></literal>):
+ See <xref linkend="mapping-declaration-id-enhanced-optimizers"/>
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect2>
+
+ <sect2 id="mapping-declaration-id-enhanced-optimizers">
+ <title>Identifier generator optimization</title>
+ <para>
+ For identifier generators which store values in the database, it is inefficient for them to hit the
+ database on each and every call to generate a new identifier value. Instead, you'd ideally want to
+ group a bunch of them in memory and only hit the database when you have exhausted your in-memory
+ value group. This is the role of the pluggable optimizers. Currently only the two enhanced generators
+ (<xref linkend="mapping-declaration-id-enhanced"/> support this notion.
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>none</literal> (generally this is the default if no optimizer was specified): This
+ says to not perform any optimizations, and hit the database each and every request.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>hilo</literal>: applies a hi/lo algorithm around the database retrieved values. The
+ values from the database for this optimizer are expected to be sequential. The values
+ retrieved from the database structure for this optimizer indicates the "group number"; the
+ <literal>increment_size</literal> is multiplied by that value in memory to define a group
+ "hi value".
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>pooled</literal>: like was discussed for <literal>hilo</literal>, this optimizers
+ attempts to minimize the number of hits to the database. Here, however, we simply store
+ the starting value for the "next group" into the database structure rather than a sequential
+ value in combination with an in-memory grouping algorithm. <literal>increment_size</literal>
+ here refers to the values coming from the database.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect2>
+
<sect2 id="mapping-declaration-compositeid" revision="3">
<title>composite-id</title>
Modified: core/trunk/documentation/manual/ja-JP/src/main/docbook/content/batch.xml
===================================================================
--- core/trunk/documentation/manual/ja-JP/src/main/docbook/content/batch.xml 2007-10-25 06:31:49 UTC (rev 14130)
+++ core/trunk/documentation/manual/ja-JP/src/main/docbook/content/batch.xml 2007-10-25 07:54:59 UTC (rev 14131)
@@ -1,388 +1,392 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<chapter id="batch">
- <title>バッチ処理</title>
-
- <para>
- Hibernateを使ってデータベースに100,000行を挿入する愚直な方法は、このようなものです:
- </para>
-
-<programlisting><![CDATA[Session session = sessionFactory.openSession();
-Transaction tx = session.beginTransaction();
-for ( int i=0; i<100000; i++ ) {
- Customer customer = new Customer(.....);
- session.save(customer);
-}
-tx.commit();
-session.close();]]></programlisting>
-
- <para>
- これは50,000番目の行のあたりで <literal>OutOfMemoryException</literal> で失敗するでしょう。
- Hibernateがセッションレベルキャッシュで、
- 新しく挿入されたすべての <literal>Customer</literal>
- インスタンスをキャッシュするからです。
- </para>
-
- <para>
- この章では、この問題を回避する方法を紹介します。
- しかしバッチ処理をするなら、JDBCバッチが使用可能であることが非常に重要です。
- そうでなければ手頃なパフォーマンスが得られません。
- JDBCバッチサイズを手頃な数値(例えば、10から50)に設定してください:
- </para>
-
-<programlisting><![CDATA[hibernate.jdbc.batch_size 20]]></programlisting>
-
- <para>
- また二次キャッシュが全く効かないプロセスで、
- このような作業をしたいと思うかもしれません:
- </para>
-
-<programlisting><![CDATA[hibernate.cache.use_second_level_cache false]]></programlisting>
-
- <para>
- しかし、これは絶対に必要というわけではありません。
- なぜなら明示的に <literal>CacheMode</literal> を設定して、
- 二次キャッシュとの相互作用を無効にすることができるからです。
-
- </para>
-
- <sect1 id="batch-inserts">
- <title>バッチ挿入</title>
-
- <para>
- 新しいオブジェクトを永続化するとき、一次キャッシュのサイズを制限するため、
- セッションを <literal>flush()</literal> して <literal>clear()</literal>
- しなければなりません。
- </para>
-
-<programlisting><![CDATA[Session session = sessionFactory.openSession();
-Transaction tx = session.beginTransaction();
-
-for ( int i=0; i<100000; i++ ) {
- Customer customer = new Customer(.....);
- session.save(customer);
- if ( i % 20 == 0 ) { //20, same as the JDBC batch size
- //flush a batch of inserts and release memory:
- session.flush();
- session.clear();
- }
-}
-
-tx.commit();
-session.close();]]></programlisting>
-
- </sect1>
-
- <sect1 id="batch-update" >
- <title>バッチ更新</title>
-
- <para>
- データを復元したり更新したりするには同じアイディアを適用します。
- それに加えて、データの行を多く返すクエリに対して有効な
- サーバーサイドのカーソルの利点を生かしたければ
- <literal>scroll()</literal> を使う必要があります。
- </para>
-
-<programlisting><![CDATA[Session session = sessionFactory.openSession();
-Transaction tx = session.beginTransaction();
-
-ScrollableResults customers = session.getNamedQuery("GetCustomers")
- .setCacheMode(CacheMode.IGNORE)
- .scroll(ScrollMode.FORWARD_ONLY);
-int count=0;
-while ( customers.next() ) {
- Customer customer = (Customer) customers.get(0);
- customer.updateStuff(...);
- if ( ++count % 20 == 0 ) {
- //flush a batch of updates and release memory:
- session.flush();
- session.clear();
- }
-}
-
-tx.commit();
-session.close();]]></programlisting>
-
- </sect1>
-
- <sect1 id="batch-statelesssession">
- <title>
- StatelessSessionインターフェイス
- </title>
-
- <para>
- また別の方法として、Hibernateはコマンド指向のAPIを用意しています。
- これは分離オブジェクトの形で、
- データベースとのデータストリームのやり取りに使うことができます。
- <literal>StatelessSession</literal> は関連する永続コンテキストを持たず、
- 高レベルのライフサイクルセマンティクスの多くを提供しません。
- 特にステートレスセッションは、一時キャッシュを実装せず、
- またどのような二次キャッシュやクエリキャッシュとも相互作用しません。
- トランザクショナルなwrite-behindや自動ダーティチェックも実装しません。
- ステートレスセッションを使って行われる操作が、
- 関連するインスタンスへカスケードされることは決してありません。
- コレクションは、ステートレスセッションからは無視されます。
- ステートレスセッションを通して行われる操作は、
- Hibernateのイベントモデルやインターセプタの影響を受けません。
- 一時キャッシュを持たないため、
- ステートレスセッションは別名を持つデータに上手く対処できません。
- ステートレスセッションは低レベルの抽象化であり、JDBCに非常によく似ています。
-
- </para>
-
-<programlisting><![CDATA[StatelessSession session = sessionFactory.openStatelessSession();
-Transaction tx = session.beginTransaction();
-
-ScrollableResults customers = session.getNamedQuery("GetCustomers")
- .scroll(ScrollMode.FORWARD_ONLY);
-while ( customers.next() ) {
- Customer customer = (Customer) customers.get(0);
- customer.updateStuff(...);
- session.update(customer);
-}
-
-tx.commit();
-session.close();]]></programlisting>
-
- <para>
- このコード例では、クエリが返す <literal>Customer</literal>
- インスタンスは即座に(セッションから)分離されることに注意してください。
- これは、どのような永続コンテキストとも決して関連しません。
-
- </para>
-
- <para>
- <literal>StatelessSession</literal> インターフェイスで定義されている
- <literal>insert(), update(), delete()</literal> は、
- 低レベルの直接的なデータベース操作と考えられます。
- 結果として、SQLの <literal>INSERT, UPDATE, DELETE</literal> がそれぞれ即座に実行されます。
- このように、これらは <literal>Session</literal> インターフェイスで定義されている
- <literal>save(), saveOrUpdate(), delete()</literal>
- とは非常に異なる意味を持ちます。
-
- </para>
-
- </sect1>
-
- <sect1 id="batch-direct" revision="3">
- <title>
- DMLスタイルの操作
- </title>
-
- <para>
- すでに議論したように、自動的かつ透過的なオブジェクト/リレーショナルマッピングは、
- オブジェクトの状態の管理であると考えられます。
- これはメモリ内のオブジェクトの状態を利用できるということです。
- そのため(SQLの <literal>データ操作言語</literal> (DML) 文:
- <literal>INSERT</literal>, <literal>UPDATE</literal>, <literal>DELETE</literal>
- を使って)データベース内のデータを直接操作しても、
- メモリ内の状態には影響を与えません。
- しかしHibernateは、バルクSQLスタイルのDML文実行に対応するメソッドを用意しています。
- これはHibernateクエリ言語(<xref linkend="queryhql">HQL</xref>)
- を通して実行されます。
-
- </para>
-
- <para>
- <literal>UPDATE</literal> と <literal>DELETE</literal> 文の疑似構文は:
- <literal>( UPDATE | DELETE ) FROM? エンティティ名 (WHERE 条件節)?</literal> です。
- 注意すべき点がいくつかあります:
-
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- from節において、FROMキーワードはオプションです。
- </para>
- </listitem>
- <listitem>
- <para>
- from節では単一のエンティティ名だけが可能で、
- 任意で別名を付けることができます。
- エンティティ名に別名が与えられると、どのようなプロパティ参照も、
- その別名を使って修飾しなければなりません。
- もしエンティティ名に別名が与えられなければ、
- どのようなプロパティ参照も修飾してはなりません。
-
- </para>
- </listitem>
- <listitem>
- <para>
- (暗黙的であれ明示的であれ)<xref linkend="queryhql-joins-forms">結合</xref>
- をバルクHQLクエリ内で指定することはできません。
- サブクエリはwhere節で使うことができます
- サブクエリそのものは、結合を含められます。
-
- </para>
- </listitem>
- <listitem>
- <para>
- where節はオプションです。
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- 例として、HQLの <literal>UPDATE</literal> を実行するには、
- <literal>Query.executeUpdate()</literal> メソッドを使ってください。
- (このメソッドはおなじみのJDBC <literal>PreparedStatement.executeUpdate()</literal>
- から名付けられました):
- d
- </para>
-
-<programlisting><![CDATA[Session session = sessionFactory.openSession();
-Transaction tx = session.beginTransaction();
-
-String hqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
-// or String hqlUpdate = "update Customer set name = :newName where name = :oldName";
-int updatedEntities = s.createQuery( hqlUpdate )
- .setString( "newName", newName )
- .setString( "oldName", oldName )
- .executeUpdate();
-tx.commit();
-session.close();]]></programlisting>
-
- <para>
- HQLの <literal>UPDATE</literal> 文は、デフォルトでは、作用するエンティティの
- <xref linkend="mapping-declaration-version">version</xref> や
- <xref linkend="mapping-declaration-timestamp">timestamp</xref>
- プロパティの値には影響しません。
- これはEJB3の仕様にも受け継がれています。
- しかし <literal>versioned update</literal> を使って、
- <literal>version</literal> や <literal>timestamp</literal>
- プロパティの値を強制的にリセットさせることができます。
- これは <literal>UPDATE</literal> キーワードの後に <literal>VERSIONED</literal>
- キーワードを追加することで行えます。
-
- </para>
-<programlisting><![CDATA[Session session = sessionFactory.openSession();
-Transaction tx = session.beginTransaction();
-String hqlVersionedUpdate = "update versioned Customer set name = :newName where name = :oldName";
-int updatedEntities = s.createQuery( hqlUpdate )
- .setString( "newName", newName )
- .setString( "oldName", oldName )
- .executeUpdate();
-tx.commit();
-session.close();]]></programlisting>
-
- <para>
- カスタムバージョン型(<literal>org.hibernate.usertype.UserVersionType</literal>)
- は <literal>update versioned</literal> 文と一緒に使えないことに注意してください。
- </para>
-
- <para>
- HQLの <literal>DELETE</literal> を実行するには、
- 同じ <literal>Query.executeUpdate()</literal> メソッドを使ってください:
-
- </para>
-
-<programlisting><![CDATA[Session session = sessionFactory.openSession();
-Transaction tx = session.beginTransaction();
-
-String hqlDelete = "delete Customer c where c.name = :oldName";
-// or String hqlDelete = "delete Customer where name = :oldName";
-int deletedEntities = s.createQuery( hqlDelete )
- .setString( "oldName", oldName )
- .executeUpdate();
-tx.commit();
-session.close();]]></programlisting>
-
- <para>
- <literal>Query.executeUpdate()</literal> メソッドが返す <literal>int</literal>
- の値は、この操作が影響を及ぼしたエンティティの数です。
- これが影響するデータベース内の行数と、相互に関係するかどうかを考えてみてください。
- HQLバルク操作は、結果として、実際のSQL文が複数実行されることになります。
- 例えばjoined-subclassです。
- 返される数は、その文によって影響された実際のエンティティの数を示します。
- joined-subclassの例に戻ると、サブクラスの一つに対する削除は、
- そのサブクラスがマッピングされたテーブルだけではなく、
- 「ルート」テーブルと継承階層をさらに下ったjoined-subclassのテーブルの削除になります。
- </para>
-
- <para>
- <literal>INSERT</literal> 文の疑似構文は:
- <literal>INSERT INTO エンティティ名 プロパティリスト select文</literal> です。
- 注意すべき点がいくつかあります:
-
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- INSERT INTO ... SELECT ... の形式だけがサポートされています。
- INSERT INTO ... VALUES ... の形式はサポートされていません。
- </para>
- <para>
- プロパティリストは、SQLの <literal>INSERT</literal> 文における <literal>カラムの仕様</literal>
- に類似しています。
- 継承のマッピングに含まれるエンティティに対して、
- クラスレベルで直接定義されたプロパティだけが、プロパティリストに使えます。
- スーパークラスのプロパティは認められず、サブクラスのプロパティは効果がありません。
- 言い換えると <literal>INSERT</literal> 文は、本質的にポリモーフィックではありません。
-
- </para>
- </listitem>
- <listitem>
- <para>
- select文の返り値の型がinsert文が期待する型とマッチしていれば、
- そのselect文は妥当なHQL selectクエリとなりえます。
- 現在このチェックをデータベースへ任せるのではなく、クエリのコンパイル時にチェックします。
- このことは、<emphasis>equal</emphasis>とは違い、
- Hibernateの <literal>Type</literal> 間の <emphasis>equivalent</emphasis> に関する
- 問題を引き起こすことに注意してください。
- これは <literal>org.hibernate.type.DataType</literal> として定義されたプロパティと、
- <literal>org.hibernate.type.TimestampType</literal>
- として定義されたプロパティの間のミスマッチの問題を引き起こします。
- データベースがそれらを区別できなくても、変換することができても、この問題は発生します。
- </para>
- </listitem>
- <listitem>
- <para>
- idプロパティに対して、insert文には二つの選択肢があります。
- プロパティリストで明示的にidプロパティを指定するか
- (この場合、対応するselect式から値が取られます)、
- プロパティリストから除外するか
- (この場合、生成される値が使われます)のいずれかです。
- 後者の選択肢は、データベース内を操作するidジェネレータを使うときのみ、利用可能です。
- この選択肢を採る場合、「インメモリ」型のジェネレータを使うと、構文解析時に例外が発生します。
- この議論では、インデータベース型ジェネレータは <literal>org.hibernate.id.SequenceGenerator</literal>
- (とそのサブクラス)と、<literal>org.hibernate.id.PostInsertIdentifierGenerator</literal>
- の実装であると考えています。
- ここで最も注意すべき例外は、<literal>org.hibernate.id.TableHiLoGenerator</literal> です。
- 値を取得する選択可能な方法がないため、このジェネレータを使うことはできません。
-
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>version</literal> や <literal>timestamp</literal> としてマッピングされるプロパティに対して、
- insert文には二つの選択肢があります。
- プロパティリストで明示的にプロパティを指定するか
- (この場合、対応するselect式から値が取られます)、
- プロパティリストから除外するか
- (この場合、<literal>org.hibernate.type.VersionType</literal> で定義された
- <literal>シード値</literal> が使われます)のいずれかです。
-
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- HQLの <literal>INSERT</literal> 文の実行例です:
-
- </para>
-
-<programlisting><![CDATA[Session session = sessionFactory.openSession();
-Transaction tx = session.beginTransaction();
-
-String hqlInsert = "insert into DelinquentAccount (id, name) select c.id, c.name from Customer c where ...";
-int createdEntities = s.createQuery( hqlInsert )
- .executeUpdate();
-tx.commit();
-session.close();]]></programlisting>
-
- </sect1>
-
-</chapter>
+
+<chapter id="batch">
+ <title>バッチ処理</title>
+
+ <para>
+ Hibernateを使ってデータベースに100,000行を挿入する愚直な方法は、このようなものです:
+ </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+for ( int i=0; i<100000; i++ ) {
+ Customer customer = new Customer(.....);
+ session.save(customer);
+}
+tx.commit();
+session.close();]]></programlisting>
+
+ <para>
+ これは50,000番目の行のあたりで <literal>OutOfMemoryException</literal> で失敗するでしょう。
+ Hibernateがセッションレベルキャッシュで、
+ 新しく挿入されたすべての <literal>Customer</literal>
+ インスタンスをキャッシュするからです。
+ </para>
+
+ <para>
+ この章では、この問題を回避する方法を紹介します。
+ しかしバッチ処理をするなら、JDBCバッチが使用可能であることが非常に重要です。
+ そうでなければ手頃なパフォーマンスが得られません。
+ JDBCバッチサイズを手頃な数値(例えば、10から50)に設定してください:
+ </para>
+
+<programlisting><![CDATA[hibernate.jdbc.batch_size 20]]></programlisting>
+<para id="disablebatching" revision="1">
+ Note that Hibernate disables insert batching at the JDBC level transparently if you
+ use an <literal>identiy</literal> identifier generator.
+</para>
+
+ <para>
+ また二次キャッシュが全く効かないプロセスで、
+ このような作業をしたいと思うかもしれません:
+ </para>
+
+<programlisting><![CDATA[hibernate.cache.use_second_level_cache false]]></programlisting>
+
+ <para>
+ しかし、これは絶対に必要というわけではありません。
+ なぜなら明示的に <literal>CacheMode</literal> を設定して、
+ 二次キャッシュとの相互作用を無効にすることができるからです。
+
+ </para>
+
+ <sect1 id="batch-inserts">
+ <title>バッチ挿入</title>
+
+ <para>
+ 新しいオブジェクトを永続化するとき、一次キャッシュのサイズを制限するため、
+ セッションを <literal>flush()</literal> して <literal>clear()</literal>
+ しなければなりません。
+ </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+for ( int i=0; i<100000; i++ ) {
+ Customer customer = new Customer(.....);
+ session.save(customer);
+ if ( i % 20 == 0 ) { //20, same as the JDBC batch size
+ //flush a batch of inserts and release memory:
+ session.flush();
+ session.clear();
+ }
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="batch-update" >
+ <title>バッチ更新</title>
+
+ <para>
+ データを復元したり更新したりするには同じアイディアを適用します。
+ それに加えて、データの行を多く返すクエリに対して有効な
+ サーバーサイドのカーソルの利点を生かしたければ
+ <literal>scroll()</literal> を使う必要があります。
+ </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+ScrollableResults customers = session.getNamedQuery("GetCustomers")
+ .setCacheMode(CacheMode.IGNORE)
+ .scroll(ScrollMode.FORWARD_ONLY);
+int count=0;
+while ( customers.next() ) {
+ Customer customer = (Customer) customers.get(0);
+ customer.updateStuff(...);
+ if ( ++count % 20 == 0 ) {
+ //flush a batch of updates and release memory:
+ session.flush();
+ session.clear();
+ }
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="batch-statelesssession">
+ <title>
+ StatelessSessionインターフェイス
+ </title>
+
+ <para>
+ また別の方法として、Hibernateはコマンド指向のAPIを用意しています。
+ これは分離オブジェクトの形で、
+ データベースとのデータストリームのやり取りに使うことができます。
+ <literal>StatelessSession</literal> は関連する永続コンテキストを持たず、
+ 高レベルのライフサイクルセマンティクスの多くを提供しません。
+ 特にステートレスセッションは、一時キャッシュを実装せず、
+ またどのような二次キャッシュやクエリキャッシュとも相互作用しません。
+ トランザクショナルなwrite-behindや自動ダーティチェックも実装しません。
+ ステートレスセッションを使って行われる操作が、
+ 関連するインスタンスへカスケードされることは決してありません。
+ コレクションは、ステートレスセッションからは無視されます。
+ ステートレスセッションを通して行われる操作は、
+ Hibernateのイベントモデルやインターセプタの影響を受けません。
+ 一時キャッシュを持たないため、
+ ステートレスセッションは別名を持つデータに上手く対処できません。
+ ステートレスセッションは低レベルの抽象化であり、JDBCに非常によく似ています。
+
+ </para>
+
+<programlisting><![CDATA[StatelessSession session = sessionFactory.openStatelessSession();
+Transaction tx = session.beginTransaction();
+
+ScrollableResults customers = session.getNamedQuery("GetCustomers")
+ .scroll(ScrollMode.FORWARD_ONLY);
+while ( customers.next() ) {
+ Customer customer = (Customer) customers.get(0);
+ customer.updateStuff(...);
+ session.update(customer);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+ <para>
+ このコード例では、クエリが返す <literal>Customer</literal>
+ インスタンスは即座に(セッションから)分離されることに注意してください。
+ これは、どのような永続コンテキストとも決して関連しません。
+
+ </para>
+
+ <para>
+ <literal>StatelessSession</literal> インターフェイスで定義されている
+ <literal>insert(), update(), delete()</literal> は、
+ 低レベルの直接的なデータベース操作と考えられます。
+ 結果として、SQLの <literal>INSERT, UPDATE, DELETE</literal> がそれぞれ即座に実行されます。
+ このように、これらは <literal>Session</literal> インターフェイスで定義されている
+ <literal>save(), saveOrUpdate(), delete()</literal>
+ とは非常に異なる意味を持ちます。
+
+ </para>
+
+ </sect1>
+
+ <sect1 id="batch-direct" revision="3">
+ <title>
+ DMLスタイルの操作
+ </title>
+
+ <para>
+ すでに議論したように、自動的かつ透過的なオブジェクト/リレーショナルマッピングは、
+ オブジェクトの状態の管理であると考えられます。
+ これはメモリ内のオブジェクトの状態を利用できるということです。
+ そのため(SQLの <literal>データ操作言語</literal> (DML) 文:
+ <literal>INSERT</literal>, <literal>UPDATE</literal>, <literal>DELETE</literal>
+ を使って)データベース内のデータを直接操作しても、
+ メモリ内の状態には影響を与えません。
+ しかしHibernateは、バルクSQLスタイルのDML文実行に対応するメソッドを用意しています。
+ これはHibernateクエリ言語(<xref linkend="queryhql">HQL</xref>)
+ を通して実行されます。
+
+ </para>
+
+ <para>
+ <literal>UPDATE</literal> と <literal>DELETE</literal> 文の疑似構文は:
+ <literal>( UPDATE | DELETE ) FROM? エンティティ名 (WHERE 条件節)?</literal> です。
+ 注意すべき点がいくつかあります:
+
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ from節において、FROMキーワードはオプションです。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ from節では単一のエンティティ名だけが可能で、
+ 任意で別名を付けることができます。
+ エンティティ名に別名が与えられると、どのようなプロパティ参照も、
+ その別名を使って修飾しなければなりません。
+ もしエンティティ名に別名が与えられなければ、
+ どのようなプロパティ参照も修飾してはなりません。
+
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ (暗黙的であれ明示的であれ)<xref linkend="queryhql-joins-forms">結合</xref>
+ をバルクHQLクエリ内で指定することはできません。
+ サブクエリはwhere節で使うことができます
+ サブクエリそのものは、結合を含められます。
+
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ where節はオプションです。
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ 例として、HQLの <literal>UPDATE</literal> を実行するには、
+ <literal>Query.executeUpdate()</literal> メソッドを使ってください。
+ (このメソッドはおなじみのJDBC <literal>PreparedStatement.executeUpdate()</literal>
+ から名付けられました):
+ d
+ </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
+// or String hqlUpdate = "update Customer set name = :newName where name = :oldName";
+int updatedEntities = s.createQuery( hqlUpdate )
+ .setString( "newName", newName )
+ .setString( "oldName", oldName )
+ .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+ <para>
+ HQLの <literal>UPDATE</literal> 文は、デフォルトでは、作用するエンティティの
+ <xref linkend="mapping-declaration-version">version</xref> や
+ <xref linkend="mapping-declaration-timestamp">timestamp</xref>
+ プロパティの値には影響しません。
+ これはEJB3の仕様にも受け継がれています。
+ しかし <literal>versioned update</literal> を使って、
+ <literal>version</literal> や <literal>timestamp</literal>
+ プロパティの値を強制的にリセットさせることができます。
+ これは <literal>UPDATE</literal> キーワードの後に <literal>VERSIONED</literal>
+ キーワードを追加することで行えます。
+
+ </para>
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+String hqlVersionedUpdate = "update versioned Customer set name = :newName where name = :oldName";
+int updatedEntities = s.createQuery( hqlUpdate )
+ .setString( "newName", newName )
+ .setString( "oldName", oldName )
+ .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+ <para>
+ カスタムバージョン型(<literal>org.hibernate.usertype.UserVersionType</literal>)
+ は <literal>update versioned</literal> 文と一緒に使えないことに注意してください。
+ </para>
+
+ <para>
+ HQLの <literal>DELETE</literal> を実行するには、
+ 同じ <literal>Query.executeUpdate()</literal> メソッドを使ってください:
+
+ </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlDelete = "delete Customer c where c.name = :oldName";
+// or String hqlDelete = "delete Customer where name = :oldName";
+int deletedEntities = s.createQuery( hqlDelete )
+ .setString( "oldName", oldName )
+ .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+ <para>
+ <literal>Query.executeUpdate()</literal> メソッドが返す <literal>int</literal>
+ の値は、この操作が影響を及ぼしたエンティティの数です。
+ これが影響するデータベース内の行数と、相互に関係するかどうかを考えてみてください。
+ HQLバルク操作は、結果として、実際のSQL文が複数実行されることになります。
+ 例えばjoined-subclassです。
+ 返される数は、その文によって影響された実際のエンティティの数を示します。
+ joined-subclassの例に戻ると、サブクラスの一つに対する削除は、
+ そのサブクラスがマッピングされたテーブルだけではなく、
+ 「ルート」テーブルと継承階層をさらに下ったjoined-subclassのテーブルの削除になります。
+ </para>
+
+ <para>
+ <literal>INSERT</literal> 文の疑似構文は:
+ <literal>INSERT INTO エンティティ名 プロパティリスト select文</literal> です。
+ 注意すべき点がいくつかあります:
+
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ INSERT INTO ... SELECT ... の形式だけがサポートされています。
+ INSERT INTO ... VALUES ... の形式はサポートされていません。
+ </para>
+ <para>
+ プロパティリストは、SQLの <literal>INSERT</literal> 文における <literal>カラムの仕様</literal>
+ に類似しています。
+ 継承のマッピングに含まれるエンティティに対して、
+ クラスレベルで直接定義されたプロパティだけが、プロパティリストに使えます。
+ スーパークラスのプロパティは認められず、サブクラスのプロパティは効果がありません。
+ 言い換えると <literal>INSERT</literal> 文は、本質的にポリモーフィックではありません。
+
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ select文の返り値の型がinsert文が期待する型とマッチしていれば、
+ そのselect文は妥当なHQL selectクエリとなりえます。
+ 現在このチェックをデータベースへ任せるのではなく、クエリのコンパイル時にチェックします。
+ このことは、<emphasis>equal</emphasis>とは違い、
+ Hibernateの <literal>Type</literal> 間の <emphasis>equivalent</emphasis> に関する
+ 問題を引き起こすことに注意してください。
+ これは <literal>org.hibernate.type.DataType</literal> として定義されたプロパティと、
+ <literal>org.hibernate.type.TimestampType</literal>
+ として定義されたプロパティの間のミスマッチの問題を引き起こします。
+ データベースがそれらを区別できなくても、変換することができても、この問題は発生します。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ idプロパティに対して、insert文には二つの選択肢があります。
+ プロパティリストで明示的にidプロパティを指定するか
+ (この場合、対応するselect式から値が取られます)、
+ プロパティリストから除外するか
+ (この場合、生成される値が使われます)のいずれかです。
+ 後者の選択肢は、データベース内を操作するidジェネレータを使うときのみ、利用可能です。
+ この選択肢を採る場合、「インメモリ」型のジェネレータを使うと、構文解析時に例外が発生します。
+ この議論では、インデータベース型ジェネレータは <literal>org.hibernate.id.SequenceGenerator</literal>
+ (とそのサブクラス)と、<literal>org.hibernate.id.PostInsertIdentifierGenerator</literal>
+ の実装であると考えています。
+ ここで最も注意すべき例外は、<literal>org.hibernate.id.TableHiLoGenerator</literal> です。
+ 値を取得する選択可能な方法がないため、このジェネレータを使うことはできません。
+
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>version</literal> や <literal>timestamp</literal> としてマッピングされるプロパティに対して、
+ insert文には二つの選択肢があります。
+ プロパティリストで明示的にプロパティを指定するか
+ (この場合、対応するselect式から値が取られます)、
+ プロパティリストから除外するか
+ (この場合、<literal>org.hibernate.type.VersionType</literal> で定義された
+ <literal>シード値</literal> が使われます)のいずれかです。
+
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ HQLの <literal>INSERT</literal> 文の実行例です:
+
+ </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlInsert = "insert into DelinquentAccount (id, name) select c.id, c.name from Customer c where ...";
+int createdEntities = s.createQuery( hqlInsert )
+ .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+ </sect1>
+
+</chapter>
Modified: core/trunk/documentation/manual/ja-JP/src/main/docbook/content/performance.xml
===================================================================
--- core/trunk/documentation/manual/ja-JP/src/main/docbook/content/performance.xml 2007-10-25 06:31:49 UTC (rev 14130)
+++ core/trunk/documentation/manual/ja-JP/src/main/docbook/content/performance.xml 2007-10-25 07:54:59 UTC (rev 14131)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
<chapter id="performance">
<title>パフォーマンスの改善</title>
@@ -681,7 +681,7 @@
<entry>OSCache</entry>
<entry><literal>org.hibernate.cache.OSCacheProvider</literal></entry>
<entry>メモリ、ディスク</entry>
- <entry>yes(クラスタ無効化)</entry>
+ <entry></entry>
<entry>yes</entry>
</row>
<row>
@@ -1377,4 +1377,4 @@
</sect1>
-</chapter>
+</chapter>
Modified: core/trunk/documentation/manual/ja-JP/src/main/docbook/content/query_hql.xml
===================================================================
--- core/trunk/documentation/manual/ja-JP/src/main/docbook/content/query_hql.xml 2007-10-25 06:31:49 UTC (rev 14130)
+++ core/trunk/documentation/manual/ja-JP/src/main/docbook/content/query_hql.xml 2007-10-25 07:54:59 UTC (rev 14131)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
<chapter id="queryhql">
<title>HQL: The Hibernate Query Language</title>
@@ -211,6 +211,41 @@
<programlisting><![CDATA[from Cat as cat where cat.mate.name like '%s%']]></programlisting>
</sect1>
+ <sect1 id="queryhql-identifier-property">
+ <title>Refering to identifier property</title>
+
+ <para>
+ There are, generally speaking, 2 ways to refer to an entity's identifier property:
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ The special property (lowercase) <literal>id</literal> may be used to reference the identifier
+ property of an entity <emphasis>provided that entity does not define a non-identifier property
+ named id</emphasis>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If the entity defines a named identifier property, you may use that property name.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ References to composite identifier properties follow the same naming rules. If the
+ entity has a non-identifier property named id, the composite identifier property can only
+ be referenced by its defined named; otherwise, the special <literal>id</literal> property
+ can be used to rerference the identifier property.
+ </para>
+
+ <para>
+ Note: this has changed significantly starting in version 3.2.2. In previous versions,
+ <literal>id</literal> <emphasis>always</emphasis> referred to the identifier property no
+ matter what its actual name. A ramification of that decision was that non-identifier
+ properties named <literal>id</literal> could never be referenced in Hibernate queries.
+ </para>
+ </sect1>
<sect1 id="queryhql-select">
<title>Select節</title>
@@ -846,9 +881,12 @@
order by count(kitten) asc, sum(kitten.weight) desc]]></programlisting>
<para>
- <literal>group by</literal> 節や <literal>order by</literal> 節に
- 算術式を含むことができないことに注意してください。
- </para>
+ Note that neither the <literal>group by</literal> clause nor the
+ <literal>order by</literal> clause may contain arithmetic expressions.
+ Also note that Hibernate currently does not expand a grouped entity,
+ so you can't write <literal>group by cat</literal> if all properties
+ of <literal>cat</literal> are non-aggregated. You have to list all
+ non-aggregated properties explicitly. </para>
</sect1>
@@ -888,35 +926,11 @@
HQL副問い合わせは、selectまたはwhere節だけで使われることに注意してください。
</para>
- <para>
- selectリストに複数の式を持つ副問い合わせには、タプルを使うことができます。
+ <para>
+ Note that subqueries can also utilize <literal>row value constructor</literal> syntax. See
+ <xref linkend="queryhql-tuple"/> for more details.
</para>
- <programlisting><![CDATA[from Cat as cat
-where not ( cat.name, cat.color ) in (
- select cat.name, cat.color from DomesticCat cat
-)]]></programlisting>
-
- <para>
- いくつかのデータベース(OracleやHSQLにはありません)では、
- 他のコンテキストでもタプルが使えます。
- 例えば、クエリコンポーネントや複合ユーザ型においてです。
- </para>
-
- <programlisting><![CDATA[from Person where name = ('Gavin', 'A', 'King')]]></programlisting>
-
- <para>
- 同等ですが、より冗長なクエリです:
- </para>
-
- <programlisting><![CDATA[from Person where name.first = 'Gavin' and name.initial = 'A' and name.last = 'King')]]></programlisting>
-
- <para>
- このようなことをしたくないのには2つの理由があります:
- 1つ目は、データベースプラットフォーム間で完全な互換性はないからです。
- 2つ目は、クエリがマッピングドキュメントのプロパティの順序に依存するからです。
- </para>
-
</sect1>
<sect1 id="queryhql-examples">
Modified: core/trunk/documentation/manual/ja-JP/src/main/docbook/content/session_api.xml
===================================================================
--- core/trunk/documentation/manual/ja-JP/src/main/docbook/content/session_api.xml 2007-10-25 06:31:49 UTC (rev 14130)
+++ core/trunk/documentation/manual/ja-JP/src/main/docbook/content/session_api.xml 2007-10-25 07:54:59 UTC (rev 14131)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
<chapter id="objectstate">
<title>オブジェクトを扱う</title>
@@ -96,6 +96,28 @@
<literal>save()</literal> の代わりに、EJB3 の初期ドラフトで定義された
<literal>persist()</literal> を使うことも可能です。
</para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>persist()</literal> makes a transient instance persistent.
+ However, it doesn't guarantee that the identifier value will be assigned to
+ the persistent instance immediately, the assignment might happen at flush time.
+ <literal>persist()</literal> also guarantees that it will not execute an
+ <literal>INSERT</literal> statement if it is called outside of transaction
+ boundaries. This is useful in long-running conversations with an extended
+ Session/persistence context.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>save()</literal> does guarantee to return an identifier. If an INSERT
+ has to be executed to get the identifier ( e.g. "identity" generator, not
+ "sequence"), this INSERT happens immediately, no matter if you are inside or
+ outside of a transaction. This is problematic in a long-running conversation
+ with an extended Session/persistence context.
+ </para>
+ </listitem>
+ </itemizedlist>
<para>
代わりに、識別子を引数にとる <literal>save()</literal>
@@ -1119,4 +1141,4 @@
</sect1>
-</chapter>
+</chapter>
Modified: core/trunk/documentation/manual/ja-JP/src/main/docbook/content/toolset_guide.xml
===================================================================
--- core/trunk/documentation/manual/ja-JP/src/main/docbook/content/toolset_guide.xml 2007-10-25 06:31:49 UTC (rev 14130)
+++ core/trunk/documentation/manual/ja-JP/src/main/docbook/content/toolset_guide.xml 2007-10-25 07:54:59 UTC (rev 14131)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
<chapter id="toolsetguide" revision="2">
<title>Toolset Guide
@@ -220,9 +220,12 @@
<entry><literal>foreign-key</literal></entry>
<entry><literal>外部キー名</literal></entry>
<entry>
- <one-to-one>、<many-to-one>、<many-to-many>マッピング要素を使って、
- 関連に対し生成された外部キー制約の名前を指定します。
- <literal>SchemaExport</literal> は <literal>inverse="true"</literal> 側を考慮しないことに注意してください。
+ specifies the name of the foreign key constraint generated
+ for an association, for a <literal><one-to-one></literal>,
+ <literal><many-to-one></literal>, <literal><key></literal>,
+ or <literal><many-to-many></literal> mapping element. Note that
+ <literal>inverse="true"</literal> sides will not be considered
+ by <literal>SchemaExport</literal>.
</entry>
</row>
<row>
Modified: core/trunk/documentation/manual/ja-JP/src/main/docbook/content/transactions.xml
===================================================================
--- core/trunk/documentation/manual/ja-JP/src/main/docbook/content/transactions.xml 2007-10-25 06:31:49 UTC (rev 14130)
+++ core/trunk/documentation/manual/ja-JP/src/main/docbook/content/transactions.xml 2007-10-25 07:54:59 UTC (rev 14131)
@@ -1,1278 +1,1260 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<chapter id="transactions" revision="2">
- <title>トランザクションと並行性</title>
-
- <para>
- Hibernateと同時実行制御について最も重要な点は、容易に理解できることです。
- Hibernateは新たなロックの振る舞いを追加しておらず、直接JDBCコネクションとJTAリソースを使用します。
- JDBC、ANSI、およびデータベース管理システム(DBMS)のトランザクション分離の仕様を
- 少し時間をかけて勉強することを強く推奨します。
- </para>
-
- <para>
- Hibernateはメモリ内のオブジェクトをロックしません。
- アプリケーションは、データベーストランザクションの分離レベルで
- 定義した振る舞いを期待できます。
- トランザクションスコープのキャッシュでもある <literal>Session</literal> のお陰で、
- 識別子やクエリにより検索したエンティティはリピータブルリードになります
- (スカラー値を返すようなレポートクエリは違います)。
- </para>
-
- <para>
- バージョニングによる自動的な楽観的同時実行制御に加えて、
- <literal>SELECT FOR UPDATE</literal> 文を使用して、
- 行を悲観的ロックするための(マイナーな)APIも提供します。
- 楽観的同時実行制御とこのAPIについては、この章の後のほうで議論します。
- </para>
-
- <para>
- データベーストランザクションや長い対話(conversation、ロングトランザクション)だけでなく、
- <literal>Configuration</literal>、<literal>SessionFactory</literal>、および
- <literal>Session</literal>
- という粒度でHibernateが行う同時実行制御の議論を始めます。
- </para>
-
- <sect1 id="transactions-basics" revision="1">
- <title>sessionスコープとtransactionスコープ</title>
-
- <para>
- <literal>SessionFactory</literal> は生成することが高価で、
- スレッドセーフなオブジェクトです。
- よって、アプリケーションのすべてのスレッドで共有すべきです。
- 通常、アプリケーションの起動時に、
- <literal>Configuration</literal> インスタンスから1度だけ生成します。
- </para>
-
- <para>
- <literal>Session</literal> は高価ではなく、スレッドセーフなオブジェクトでもありません。
- よって、1つの要求や1つの対話、1つの作業単位(unit of work)に対して1度だけ使い、
- その後で捨てるべきです。
- <literal>Session</literal> は必要になるまで、
- JDBC <literal>Connection</literal>(もしくは <literal>DataSource</literal>)を獲得しません。
- ゆえに、実際に使用するときまでリソースを消費しません。
- </para>
-
- <para>
- この状況を完了させるために、 データベーストランザクションについても考えなければなりません。
- データベース内のロックの競合を少なくするために、
- データベーストランザクションは可能な限り短くするべきです。
- 長いデータベーストランザクションは、アプリケーションの高い並列実行性を阻害します。
- ゆえに、ユーザーが考えている間(作業単位が完了するまで)データベーストランザクションを
- 開いたままにするのは、たいていの場合よい設計とはいえません。
- </para>
-
- <para>
- 作業単位というスコープとは何でしょうか?
- 1つのHibernate <literal>Session</literal> は、
- いくつかのデータベーストランザクションをまたがることができるでしょうか?
- または、スコープと一対一の関係でしょうか?
- いつ <literal>Session</literal> を開き、閉じるべきでしょうか?
- そして、データベーストランザクション境界をどのように分けるのでしょうか?
- </para>
-
- <sect2 id="transactions-basics-uow" revision="1">
- <title>作業単位(Unit of work)</title>
-
- <para>
- 1つ目は、<emphasis>session-per-operation</emphasis> アンチパターンを使ってはいけません。
- すなわち、1つのスレッドの中で、単純なデータベース呼び出しのたびに
- <literal>Session</literal> を開いて、閉じてはいけません!
- もちろん、データベーストランザクションについても同様です。
- アプリケーション中のデータベース呼び出しは、
- 計画されたシーケンス(planned sequence)を使い、
- アトミックな作業単位に分類されます。
- (1つのSQL文ごとにコミットする自動コミットが、
- 使われないという意味でもあることに注意してください。
- 自動コミットは、SQLコンソールでアドホックな作業をする際に使うものです。
- Hibernateは直ちに自動コミットモードを無効にします。
- もしくは、アプリケーションサーバーが無効化することを期待します。)
- データベーストランザクションはオプションではありません。
- データベースとのすべての通信は、データの読み込みであっても、書き込みであっても、
- トランザクションの中で行わなければなりません。
- 説明すると、データ読み込みに対して、自動コミットは避けるべきです。
- なぜなら、多数の小さなトランザクションは、明確に定義された1つの作業単位と比べて、
- パフォーマンスがよくなることはありません。
- 後者は保守性や拡張性もよりすぐれています。
- </para>
-
- <para>
- マルチユーザーのクライアント/サーバーアプリケーションの中で、
- 最もよく使われるパターンは、<emphasis>session-per-request</emphasis> です。
- このモデルの中では、
- クライアントから(Hibernate永続化層が動作する)サーバーへリクエストが送られ、
- 新しいHibernate <literal>Session</literal> が開かれます。
- そして、この作業単位の中ですべてのデータベース処理が実行されます。
- 作業が完了した(そして、クライアントへのレスポンスが準備できた)時点で、
- session をフラッシュし、閉じます。
- クライアントの要求を処理するために、1つのデータベーストランザクションを使用するでしょう。
- <literal>Session</literal> を開き、閉じる際に、
- データベーストランザクションを開始し、コミットします。
- 二つの関係は一対一です。
- このモデルは多くのアプリケーションに完全に適合します。
- </para>
-
- <para>
- 以降の実装にチャレンジしてください。
- <literal>Session</literal> を持ち、トランザクションを正確に開始し、終わらせるだけでなく、
- データアクセス操作も得やすくする必要があります。
- リクエストがサーバーにヒットした際と、レスポンスを送信する前に、実行されるinterceptor
- (例えば、<literal>ServletFilter</literal>)を使って、作業単位の境界を実装するのが理想的です。
- <literal>ThreadLocal</literal> 変数を使って、
- リクエストを処理するスレッドに <literal>Session</literal> を結びつけることを推奨します。
- これにより、スレッド内で実行されるすべてのコードで、
- (static変数にアクセスするように)簡単に <literal>Session</literal> にアクセスできるようになります。
- 選択したデータベーストランザクション境界の機構次第で、<literal>ThreadLocal</literal>
- 変数の中にトランザクションコンテキストを保持するかもしれません。
- この実装パターンは、<emphasis>ThreadLocal Session</emphasis> および
- <emphasis>Open Session in View</emphasis> という名前で知られています。
- 本ドキュメントで先に見せた <literal>HibernateUtil</literal> ヘルパークラスを拡張することで、
- このパターンを容易に実装できます。
- もちろん、interceptor を実装する方法を見つけ、環境をセットアップする必要があります。
- HibernateのWebサイトにあるtipsと例を参照してください。
- </para>
-
- <para>
- 以降の実装にチャレンジしてください。
- Hibernateは単純なこのパターンのために、予め組み込まれた
- 「current session」の管理を提供します。
- サーバーリクエストを処理する際はトランザクションを開始しなければなりません。
- そして、レスポンスをクライアントに送信する前にトランザクションを終わらせます。
- 好きな方法で実現できます。一般的な解決策は <literal>ServletFilter</literal> や
- サービスメソッドをポイントカットしてAOPインターセプター、
- proxy/interception コンテナです。
- EJBコンテナはEJBセッションビーンをトランザクション境界として
- アスペクトをクロスカットする実装の標準的な方法です(CMTによる宣言的)。
- プログラムによるトランザクション境界を使うと決めた場合、
- 簡単に使うため、互換性のあるコードにするために、
- この章の後のほうにあるHibernate <literal>Transaction</literal> APIのほうがよいです。
- </para>
-
- <para>
- アプリケーションのコードは、必要なときにどこでも、何回でも、
- 単に <literal>sessionFactory.getCurrentSession()</literal> を呼び出すだけで
- 「現在のセッション」にアクセスできます。
- 現在のデータベーストランザクションへの <literal>セッション</literal> を常に取得します。
- リソース・ローカルな環境、もしくはJTA環境を構成しなければなりません
- (<xref linkend="architecture-current-session"/> を参照してください)。
- </para>
-
- <para>
- ときどき、「ビューを描画する」まで <literal>セッション</literal>
- とデータベーストランザクションのスコープを拡張すると便利なことがあります。
- これは、要求の処理と描画のフェーズを分けている
- サーブレットアプリケーションにおいて特に役立ちます。
- 独自のインターセプタを実装すれば、
- ビューを描画するまでデータベーストランザクションを拡張するのは簡単です。
- しかし、コンテナ管理トランザクションのEJBに頼る場合は、簡単にはできません。
- なぜなら、ビューの描画を開始する前に、EJBのメソッドがリターンした際に、
- トランザクションが完了するためです。
- この <emphasis>Open Session in View</emphasis> パターンに関連するヒントと例については、
- HibernateのWebサイトやフォーラムを参照してください。
- </para>
-
- </sect2>
-
- <sect2 id="transactions-basics-apptx" revision="1">
- <title>長い対話</title>
-
- <para>
- session-per-requestパターンは、作業単位を設計する際に役立つ考えというだけではありません。
- 多くのビジネスプロセスは、ユーザーとの一連の相互作用全体を要求します。
- その相互作用には、データベースアクセスが含まれます。
-
- Webとエンタープライズアプリケーションでは、データベーストランザクションが
- ユーザとの相互作用にまで渡ることは許されません。
-
- 次の例をよく考えてみてください。
- </para>
-
- <itemizedlist>
- <listitem>
- <para>
- ダイアログの最初の画面が開き、個々の <literal>Session</literal>
- とデータベーストランザクションの中でロードされたデータをユーザーに見せます。
- ユーザーはオブジェクトを自由に修正できます。
- </para>
- </listitem>
- <listitem>
- <para>
- 5分後にユーザーは「Save」をクリックし、修正が永続化されるのを期待します。
- また、この情報を編集したのは自分1人だけで、
- 修正のコンフリクトは発生しないと期待します。
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- この作業単位を(ユーザーの視点で)長期の <emphasis>対話</emphasis>
- (もしくは、<emphasis>アプリケーショントランザクション</emphasis> )と呼びます。
- アプリケーションにこれを実装する方法はたくさんあります。
- </para>
-
- <para>
- 最初に思いつく実装は、ユーザーが考えている間、<literal>Session</literal>
- とデータベーストランザクションを開いたままにしておくことです。
- 同時に修正されず、分離と原子性が保証されるように、
- データベース内のロックは保持したままにします。
- もちろん、これはアンチパターンです。
- なぜなら、ロックの競合が発生すると、
- アプリケーションが同時ユーザー数に応じてスケールアップできなくなるからです。
- </para>
-
- <para>
- 明らかに、対話を実装するためには、
- いくつかのデータベーストランザクションを使用するべきです。
- この場合、ビジネスプロセスの分離を維持することは、
- アプリケーション層の責務の1つになります。
- 1つの対話は、
- 通常いくつかのデータベーストランザクションに及びます。
- データベーストランザクションの1つのみ(最後の1つ)が更新したデータを保存し、
- 他はデータを読むだけであれば、それはアトミックです
- (例えば、いくつかの要求/応答を繰り返すウィザード形式のダイアログ)。
- これは聞くより、実装したほうが簡単です。
- Hibernateの機能を使うのであれば、特に簡単です。
- </para>
-
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>自動バージョニング</emphasis>
- - Hibernateは自動的に楽観的同時実行制御ができます。
- ユーザーが考えている間に同時に修正がおきた場合、自動的に検出できます。
- 通常、対話の終了時にチェックするだけです。
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>分離(Detached)オブジェクト</emphasis> - すでに議論した
- <emphasis>session-per-request</emphasis> パターンを使うと決定した場合、
- ロードされたすべてのインスタンスは、ユーザが考えている間は、
- セッションから分離された状態になります。
- オブジェクトをセッションに再追加し、修正を永続化できます。
- これを <emphasis>session-per-request-with-detached-objects</emphasis>
- パターンと呼びます。
- 自動バージョニングを使うことで、同時に行われる修正を分離できます。
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>拡張(もしくは、長い)セッション</emphasis>
- - Hibernateの <literal>Session</literal> は、
- データベーストランザクションをコミットした後、
- 裏で結びついているJDBCコネクションを切断できます。
- そして、クライアントからの新しい要求が発生した際に、再接続できます。
- このパターンは、<emphasis>session-per-conversation</emphasis>
- という名で知られており、オブジェクトをセッションへ再追加することさえ不要にします。
- 自動バージョニングを使うことで、同時に行われる修正を分離できます。
-
- 通常 <literal>Session</literal> を自動的にフラッシュさせず、
- 明示的にフラッシュします。
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- <emphasis>session-per-request-with-detached-objects</emphasis> と
- <emphasis>session-per-conversation</emphasis> の2つは、
- 利点と欠点を持っています。
- これについては、この章の後のほうで、楽観的同時実行制御の文脈の中で議論します。
- </para>
-
- </sect2>
-
- <sect2 id="transactions-basics-identity">
- <title>オブジェクト識別子を考える</title>
-
- <para>
- アプリケーションは、2つの異なる <literal>Session</literal> から
- 同じ永続状態に同時にアクセスできます。
- しかし、2つの <literal>Session</literal> インスタンスが
- 永続性クラスの1つのインスタンスを共有することはできません。
- ゆえに、識別子には2つの異なる概念があるということになります。
- </para>
-
- <variablelist spacing="compact">
- <varlistentry>
- <term>データベース識別子</term>
- <listitem>
- <para>
- <literal>foo.getId().equals( bar.getId() )</literal>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>JVM識別子</term>
- <listitem>
- <para>
- <literal>foo==bar</literal>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
-
- <para>
- <emphasis>個々の</emphasis> <literal>Session</literal> に追加されたオブジェクトにとって
- (すなわち、1つの <literal>Session</literal> のスコープの中では)、2つの概念は同じです。
- データベース同一性とJVM同一性が一致することを、Hibernateが保証します。
- しかし、アプリケーションが2つの異なるセッションから
- 「同じ」(永続性識別子の)ビジネスオブジェクトに同時にアクセスする限り、
- 2つのインスタンスは実際に(JVM識別子が)「異なり」ます。
- 楽観的アプローチによって、(自動バージョニングの)フラッシュ/コミット時に
- コンフリクトが解決されます。
- </para>
-
- <para>
- このアプローチでは、Hibernateとデータベースに同時実行についての心配が残ります。
- 一方で、最高のスケーラビリティが提供されます。
- なぜなら、1スレッドの作業単位の中で一意性が保証されれば、
- 高価なロックや同期化が不要になるためです。
- <literal>Session</literal> ごとに1つのスレッドを貼り付ける限り、
- アプリケーションはビジネスオブジェクトをsynchronizeする必要はありません。
- <literal>Session</literal> 内では、アプリケーションはオブジェクトを比較するために、
- <literal>==</literal> を安全に使用できます。
- </para>
-
- <para>
- けれども、<literal>Session</literal> の外で <literal>==</literal>
- を使うアプリケーションは、予期しない結果に遭遇します。
- これは予期しない場所で起こりえます。
- 例えば、2つの分離インスタンスを同じ <literal>Set</literal> に
- putしたときなどです。
- 両方とも同じデータベース識別子を持ちます(すなわち、同じ行を表します)。
- しかし、分離状態のインスタンスのJVM識別子は当然保証されません。
- 開発者は、永続性クラスの <literal>equals()</literal> と <literal>hashCode()</literal>
- メソッドをオーバーライドし、オブジェクト等価性の概念を実装すべきです。
- 警告が1つあります。等価性の実装にデータベース識別子を使わないでください。
- ユニークな(普通は不変の)属性の組み合わせであるビジネスキーを使ってください。
- もし、一時オブジェクトが永続化された場合、データベース識別子が変わります。
- 一時オブジェクトを(通常分離インスタンスと共に) <literal>Set</literal>
- に保持する場合、ハッシュコードが変わるということは、<literal>Set</literal>
- の契約を破るということです。
- ビジネスキーのための属性は、データベースの主キーほど安定すべきではないです。
- オブジェクトが同じ <literal>Set</literal> の中にいる間だけ、安定を保証すべきです。
- この問題のより徹底的な議論は、HibernateのWebサイトを参照してください。
- また、これはHibernateの問題ではなく、単にJavaオブジェクトの識別子や等価性を
- どのように実装すべきかということです。
- </para>
-
- </sect2>
-
- <sect2 id="transactions-basics-issues">
- <title>一般的な問題</title>
-
- <para>
- <emphasis>session-per-user-session</emphasis> と
- <emphasis>session-per-application</emphasis> アンチパターン
- は使ってはいけません(もちろん、まれに例外があります)。
- 注意:下記の問題のいくつかは、推奨されるパターンとしても出現します。
- 設計を決定する前に、裏の意味を理解するようにしてください。
- </para>
-
- <itemizedlist>
- <listitem>
- <para>
- <literal>Session</literal> はスレッドセーフではありません。
- HTTPリクエスト、セッションBean、Swingワーカーのように、
- 同時実行が可能なものが <literal>Session</literal> インスタンスを共有すると、
- 競合状態を引き起こします。
- (後で議論する)<literal>HttpSession</literal> の中で
- Hibernate <literal>Session</literal> を保持する場合、
- HttpSessionへのアクセスを同期化することを考慮すべきです。
- さもなければ、ユーザーが十分早くリロードをクリックすると、
- 同時に走る2つのスレッドの中で、同じ <literal>Session</literal> が使われます。
- </para>
- </listitem>
- <listitem>
- <para>
- Hibernateが例外を投げた場合は、データベーストランザクションをロールバックし、
- 直ちに <literal>Session</literal> を閉じるべきです(詳細を後で議論します)。
- <literal>Session</literal> がアプリケーションに結び付けられているのであれば、
- アプリケーションを停止すべきです。
- データベーストランザクションをロールバックしても、ビジネスオブジェクトは
- トランザクションを開始したときの状態に戻りません。
- これは、データベースの状態とビジネスオブジェクトは同期していないことを意味します。
- 通常これは問題になりません。
- なぜなら、例外は回復できないからです。
- とにかくロールバックした後にやり直すべきです。
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>Session</literal> は永続(persistent)状態のすべてのオブジェクトを
- キャッシュします(Hibernateは監視し、ダーティ状態かチェックします)。
- これは、長い間セッションを開いたままにするか、
- 非常に多くのデータをロードし続けるかした場合は、
- OutOfMemoryExceptionが発生するまで無限に大きくなることを意味します。
- 解決策の1つは、<literal>Session</literal> キャッシュを管理するために、
- <literal>clear()</literal> か <literal>evict()</literal> を呼ぶことです。
- しかし、大きなデータを処理する必要があるなら、
- たぶんストアドプロシージャを考慮するべきでしょう。
- いくつかの解決策は、<xref linkend="batch"/> で紹介されています。
- ユーザーセッションの間、<literal>Session</literal> を開いたままにするということは、
- データが新鮮でなくなる確率が高くなることを意味します。
- </para>
- </listitem>
- </itemizedlist>
-
- </sect2>
-
- </sect1>
-
- <sect1 id="transactions-demarcation">
- <title>データベーストランザクション境界</title>
-
- <para>
- データベース(もしくはシステム)トランザクションの境界は、常に必要です。
- データベーストランザクションの外で、データベースとの通信は起きません
- (これは自動コミットモードに慣れている多くの開発者を混乱させるかもしれません)。
- 読み込むだけの操作にでも、いつも明確なトランザクション境界を使用してください。
- 分離レベルとデータベースの能力次第で、これは必要ないかもしれませんが、
- 常にトランザクション境界を明示的に指定しても、マイナス面は全くありません。
-
- 確かに、1つのデータベーストランザクションは多数の小さなトランザクションより
- (データの読み込みであっても)パフォーマンスがすぐれています。
- </para>
-
- <para>
- J2EE環境に管理されていない状態
- (すなわち、スタンドアロン、単純なWebやSwingアプリケーション)でも、
- 管理された状態でも、Hibernateアプリケーションを実行できます。
- 管理されていない環境では、Hiberanteがデータベースのコネクションプールを提供します。
- アプリケーション開発者は、トランザクション境界を手動で設定しなければなりません。
- 言い換えると、データベーストランザクションの開始、コミット、ロールバックを
- 開発者自身が設定する必要があるということです。
-
- 通常、管理された環境では、コンテナ管理によるトランザクション(CMT)が提供されます。
- 例えば、セッションBeanのデプロイメントディスクリプタで宣言的に定義し、
- トランザクションを組み立てます。
- プログラムによるトランザクション境界はもう必要ありません。
- </para>
-
- <para>
- しかしながら、管理されていないリソース・ローカルな環境と
- JTAに依存したシステム(CMTではなくBMT)の両方に、
- 永続化層をポータブルに保つのは、しばしば望ましいことです。
-
- デプロイ環境のネイティブのトランザクションシステムを呼び出す
- <literal>Transaction</literal> というラッパーAPIをHibernateが提供します。
- このAPIを使うかは任意ですが、CMTのセッションBeanを使わないのであれば、使うことを強く推奨します。
- </para>
-
- <para>
- 通常、<literal>Session</literal> 終了は、4つの異なるフェーズを含みます。
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- セッションのフラッシュ
- </para>
- </listitem>
- <listitem>
- <para>
- トランザクションのコミット
- </para>
- </listitem>
- <listitem>
- <para>
- セッションのクローズ
- </para>
- </listitem>
- <listitem>
- <para>
- 例外のハンドリング
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- セッションのフラッシュについては、前のほうですでに議論しました。
- 管理された環境と管理されていない環境の両方について、
- トランザクション境界と例外ハンドリングをもっと詳しく見ていきましょう。
- </para>
-
-
- <sect2 id="transactions-demarcation-nonmanaged" revision="2">
- <title>管理されていない環境</title>
-
- <para>
- Hibernate永続化層を管理されていない環境で実装する場合は、
-
- 通常単純なコネクションプール(すなわちDataSourceではない)によって、
- データベースコネクションを制御します。
- Hibernateはそのコネクションプールから必要なコネクションを取得します。
-
- セッション/トランザクション制御のイディオムは次のようになります。
- </para>
-
- <programlisting><![CDATA[// Non-managed environment idiom
-Session sess = factory.openSession();
-Transaction tx = null;
-try {
- tx = sess.beginTransaction();
-
- // do some work
- ...
-
- tx.commit();
-}
-catch (RuntimeException e) {
- if (tx != null) tx.rollback();
- throw e; // or display error message
-}
-finally {
- sess.close();
-}]]></programlisting>
-
- <para>
- 明示的に <literal>Session</literal> の <literal>flush()</literal> を呼び出すべきではなく、
- <literal>commit()</literal> を呼び出すことにより、自動的に同期化処理が実行されます
- (セッションの <xref linkend="objectstate-flushing">FlushMode</xref> に依存している)。
-
- <literal>close()</literal> を呼び出すことにより、セッションの終わりを明確にします。
- <literal>close()</literal> が暗黙的に行う主なことは、
- セッションがJDBCコネクションを開放することです。
-
- 上記のJavaコードはポータブルであり、管理されていない環境とJTA環境の両方で実行できます。
- </para>
-
- <para>
- より適応性のある解決策は、Hibernateに予め組み込まれている
- 「current session」コンテキスト管理です。
- 言葉で説明するより下記を見たほうが速いでしょう。
- </para>
-
- <programlisting><![CDATA[// Non-managed environment idiom with getCurrentSession()
-try {
- factory.getCurrentSession().beginTransaction();
-
- // do some work
- ...
-
- factory.getCurrentSession().getTransaction().commit();
-}
-catch (RuntimeException e) {
- factory.getCurrentSession().getTransaction().rollback();
- throw e; // or display error message
-}]]></programlisting>
-
- <para>
- 正規のアプリケーションの中では、このようなコードの切れ端を決して見ないでしょう。
- 致命的な(システム)例外は、常に「最上位」でキャッチすべきです。
- 言い換えれば、(永続化層で)Hibernate呼び出しを実行するコードと、
- <literal>RuntimeException</literal> を制御する
- (通常はクリーンアップと終了のみ行うことができる)コードは、別々の層の中にあります。
- Hibernateによるカレントコンテキスト管理は、この設計をかなり単純にします。
- 必要なのは、<literal>SessionFactory</literal> にアクセスすることだけです。
- 例外処理は、この章の後のほうで議論します。
- </para>
-
- <para>
- 注意:(デフォルトですが)
- <literal>org.hibernate.transaction.JDBCTransactionFactory</literal>
- を選択するべきです。
- 第2の用例としては、
- <literal>hibernate.current_session_context_class</literal> を
- <literal>"thread"</literal> とするとよいでしょう。
- </para>
-
- </sect2>
-
- <sect2 id="transactions-demarcation-jta" revision="3">
- <title>JTAを使用する</title>
-
- <para>
- 永続化層をアプリケーションサーバー(例えば、EJBセッションBeanの背後)で実行する場合、
- Hibernateから取得するすべてのデータソースコネクションは、
- 自動的にグローバルJTAトランザクションの一部になります。
-
- EJBを使わずに、スタンドアロンのJTA実装を導入することもできます。
- JTA統合のために、Hibernateは2つの戦略を提供します。
- </para>
-
- <para>
- Bean管理トランザクション(BMT)を使い、<literal>Transaction</literal> APIを使う場合、
- HibernateはアプリケーションサーバーにBMTトランザクションの開始と終わりを告げます。
- すなわち、トランザクション管理のコードは、管理されない環境と同じになります。
- </para>
-
- <programlisting><![CDATA[// BMT idiom
-Session sess = factory.openSession();
-Transaction tx = null;
-try {
- tx = sess.beginTransaction();
-
- // do some work
- ...
-
- tx.commit();
-}
-catch (RuntimeException e) {
- if (tx != null) tx.rollback();
- throw e; // or display error message
-}
-finally {
- sess.close();
-}]]></programlisting>
-
- <para>
- トランザクション境界として <literal>Session</literal> を使いたい場合、
- 簡単にコンテキストを伝播する機能である <literal>getCurrentSession()</literal> があるので、
- JTAの <literal>UserTransaction</literal> APIを直接使用すべきでしょう。
- </para>
-
- <programlisting><![CDATA[// BMT idiom with getCurrentSession()
-try {
- UserTransaction tx = (UserTransaction)new InitialContext()
- .lookup("java:comp/UserTransaction");
-
- tx.begin();
-
- // Do some work on Session bound to transaction
- factory.getCurrentSession().load(...);
- factory.getCurrentSession().persist(...);
-
- tx.commit();
-}
-catch (RuntimeException e) {
- tx.rollback();
- throw e; // or display error message
-}]]></programlisting>
-
- <para>
- CMTでは、トランザクション境界をセッションBeanのデプロイメントディスクリプタで定義し、
- プログラムでは行いません。
- ゆえに、コードは次のように少なくなります。
- </para>
-
- <programlisting><![CDATA[// CMT idiom
- Session sess = factory.getCurrentSession();
-
- // do some work
- ...
-]]></programlisting>
-
- <para>
- CMT/EJBの中では、常にロールバックが自動的に実施されます。
- なぜなら、セッションビーンのメソッドにより投げられた制御されていない
- <literal>RuntimeException</literal> は、グローバルトランザクションを
- ロールバックするようにコンテナに伝えるためです。
- <emphasis>これは、BMTもしくはCMTといっしょにHibernate <literal>Transaction</literal>
- APIを使う必要は少しもないという意味です。</emphasis>
- </para>
-
- <para>
- Hibernateのトランザクションファクトリを設定する際に、
- JTAを直接使う(BMTの)場合は <literal>org.hibernate.transaction.JTATransactionFactory</literal> を、
- CMTセッションビーンの中では <literal>org.hibernate.transaction.CMTTransactionFactory</literal> を
- 選択すべきだということに注意してください。
- <literal>hibernate.transaction.manager_lookup_class</literal>
- をセットすることも思い出してください。
- なお、<literal>hibernate.current_session_context_class</literal> は、
- セットしないか(後方互換)、<literal>"jta"</literal> をセットしてください。
- </para>
-
- <para>
- <literal>getCurrentSession()</literal> オペレーションは、JTA環境では1つの欠点を持ちます。
-
- デフォルトで使われる <literal>after_statement</literal> コネクションリリースモードを使用する上で、
- 警告が1つあります。
-
- JTA仕様の愚かな制約のために、
- <literal>scroll()</literal> または <literal>iterate()</literal> が返した、
- 閉じられていない <literal>ScrollableResults</literal> または <literal>Iterator</literal>
- インスタンスをHibernateが自動的にクリーンアップすることはできません。
-
- <literal>finally</literal> ブロックの中で、
- <literal>ScrollableResults.close()</literal> または
- <literal>Hibernate.close(Iterator)</literal> を明示的に呼び出して、
- 裏に潜んだデータベースカーソルを解放 <emphasis>しなければなりません</emphasis>。
-
- (もちろん、多くのアプリケーションでは、JTAかCMTコードで <literal>scroll()</literal>
- や <literal>iterate()</literal> の使用を避けるのは容易です。)
- </para>
-
- </sect2>
-
- <sect2 id="transactions-demarcation-exceptions">
- <title>例外ハンドリング</title>
-
- <para>
- <literal>Session</literal> が例外(<literal>SQLException</literal>を含む)を投げた場合、
- 直ちに、データベーストランザクションをロールバックし、<literal>Session.close()</literal>
- を呼び、<literal>Session</literal> インスタンスを破棄すべきです。
- <literal>Session</literal> のいくつかのメソッドは、
- セッションの状態を <emphasis>矛盾したまま</emphasis> にします。
- Hibernateが投げた例外を、回復できるものとして扱うことはできません。
- <literal>finally</literal> ブロックの中で <literal>close()</literal> を呼んで、
- <literal>Session</literal> を確実に閉じてください。
- </para>
-
- <para>
- <literal>HibernateException</literal> は、Hibernate永続化層の中で発生する多くのエラーを
- ラップする、検査されない例外です(Hibernateの古いバージョンは違いました)。
- 私たちの意見は、アプリケーション開発者に回復不可能な例外を
- 下層でキャッチすることを強要すべきではないということです。
- 多くのシステムでは、検査されない例外と致命的な例外は、
- コールスタックの最初のフレームの1つ(例えば、最上位の層で)でハンドリングし、
- エラーメッセージをアプリケーションユーザーに表示します
- (もしくは、他の適切な処理を実施します)。
- Hibernateは、<literal>HibernateException</literal> 以外の検査されない例外も
- 投げることに注意してください。
- これらもまた、回復不可能であり、適切な処理を実施すべきです。
- </para>
-
- <para>
- Hibernateは、データベースとの対話中に投げられた <literal>SQLException</literal> を
- <literal>JDBCException</literal> でラップします。
- 実は、例外をより意味のある <literal>JDBCException</literal> のサブクラスに
- 変換しようと試みます。
- 元の <literal>SQLException</literal> は、<literal>JDBCException.getCause()</literal>
- によりいつでも得られます。
- Hibernateは、<literal>SessionFactory</literal> に追加されている
- <literal>SQLExceptionConverter</literal> を使い、<literal>SQLException</literal> を
- 適当な <literal>JDBCException</literal> サブクラスに変換します。
- デフォルトでは、<literal>SQLExceptionConverter</literal> は設定されているSQL方言により
- 定義されます。
- 一方で、独自の実装に差し替えることもできます
- (詳細は、<literal>SQLExceptionConverterFactory</literal> クラスのJavadocを参照してください)。
- 標準的な <literal>JDBCException</literal> のサブタイプを下記に示します。
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- <literal>JDBCConnectionException</literal> -
- 基礎となるJDBC通信のエラーを表します。
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>SQLGrammarException</literal> -
- 発行するSQLの文法もしくは構文の問題を表します。
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>ConstraintViolationException</literal> -
- 何らかの形式の完全性制約違反を表します。
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>LockAcquisitionException</literal> -
- 要求された操作を実施するのに必要なロックレベルを得る際のエラーを表します。
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>GenericJDBCException</literal> -
- 他のカテゴリに一致しなかった一般的な例外です。
- </para>
- </listitem>
- </itemizedlist>
-
- </sect2>
-
- <sect2 id="transactions-demarcation-timeout">
- <title>トランザクションのタイムアウト</title>
-
- <para>
- EJBのような管理された環境が提供するきわめて重要な特徴の1つは、
- トランザクションのタイムアウトです。
- これは管理されていないコードには提供できません。
- トランザクションタイムアウトは、不品行なトランザクションが
- ユーザーにレスポンスを返さないまま、無期限にリソースを使い続けない
- ことを保障します。
- 管理された環境(JTA)の外では、Hibernateはこの機能をフルに提供できません。
- しかしながら、Hibernateは次のようなデータアクセス操作の制御くらいはできます。
- データベースレベルのデッドロックや大きなリザルトセットを返すクエリを
- 定義されたタイムアウトによって確実に制限します。
- 管理された環境では、HibernateはトランザクションタイムアウトをJTAに委譲します。
- この機能は、Hibernateの <literal>Transaction</literal> オブジェクトに
- よって抽象化されています。
- </para>
-
- <programlisting><![CDATA[
-Session sess = factory.openSession();
-try {
- //set transaction timeout to 3 seconds
- sess.getTransaction().setTimeout(3);
- sess.getTransaction().begin();
-
- // do some work
- ...
-
- sess.getTransaction().commit()
-}
-catch (RuntimeException e) {
- sess.getTransaction().rollback();
- throw e; // or display error message
-}
-finally {
- sess.close();
-}]]></programlisting>
-
- <para>
- CMTビーンの中では <literal>setTimeout()</literal> を
- 呼び出せないことに注意してください。
- トランザクションタイムアウトは宣言的に定義されるべきです。
- </para>
-
- </sect2>
-
- </sect1>
-
- <sect1 id="transactions-optimistic">
- <title>楽観的同時実行制御</title>
-
- <para>
- 高い並列性と高いスケーラビリティの両方を実現するアプローチは、
- バージョニングを使った楽観的同時実行制御のみです。
- 更新の衝突を見つけるために(および、更新が失われるのを防ぐために)、
- バージョン番号もしくはタイムスタンプを使って、バージョンをチェックします。
- Hibernateは、楽観的同時実行を行うアプリケーションコードを書くための
- アプローチを3つ提供します。
- 私たちが見せるユースケースは、長い対話を持ちますが、
- バージョンチェックはまだ1つのデータベーストランザクションの中で更新を失うことを防ぐ
- 利点も持っています。
- </para>
-
- <sect2 id="transactions-optimistic-manual">
- <title>アプリケーションによるバージョンチェック</title>
-
- <para>
- Hibernateにほとんど助けてもらわずに実装するケースです。
- データベースとのやり取りは、それぞれ新しい <literal>Session</literal> の中で起こります。
- 開発者は、すべての永続性インスタンスを操作する前に、
- データベースから再読み込みする責務があります。
- このアプローチでは、対話トランザクションの分離を守るために、
- アプリケーション自身がバージョンチェックを行う必要があります。
- このアプローチは、データベースアクセスの中では、最も非効率です。
- エンティティEJBと最も似ているアプローチです。
- </para>
-
- <programlisting><![CDATA[// foo is an instance loaded by a previous Session
-session = factory.openSession();
-Transaction t = session.beginTransaction();
-
-int oldVersion = foo.getVersion();
-session.load( foo, foo.getKey() ); // load the current state
-if ( oldVersion != foo.getVersion() ) throw new StaleObjectStateException();
-foo.setProperty("bar");
-
-t.commit();
-session.close();]]></programlisting>
-
- <para>
- <literal><version></literal> を使って、<literal>version</literal>
- プロパティをマッピングします。
- Hibernateは、エンティティがダーティである場合、フラッシュし、
- その間に <literal>version</literal> プロパティを自動的にインクリメントします。
- </para>
-
- <para>
- もちろん、データの並列性が低い環境で運用しており、バージョンチェックが不要なら、
- このアプローチを使い、バージョンチェックをスキップするだけです。
- その場合は、長い対話には、
- <emphasis>「最後にコミットしたものが勝つ」</emphasis> がデフォルトの戦略でしょう。
- このアプローチは、アプリケーションのユーザーを混乱させるかもしれないことを
- 心に留めて置いてください。それは、エラーメッセージや競合した変更をマージする機会が
- ないまま、更新を失う経験をするためです。
- </para>
-
- <para>
- 確かに、マニュアルによるバージョンチェックは、些細な儀式だけで実行できますが、
- 多くのアプリケーションにとって実用的ではありません。
- しばしば、1つのインスタンスだけでなく、
- 修正されたオブジェクトの完全なグラフをチェックしなければなりません。
- Hibernateは、設計パラダイムとして、拡張 <literal>Session</literal> か
- 分離されたインスタンスを自動的にバージョンチェックします。
- </para>
-
- </sect2>
-
- <sect2 id="transactions-optimistic-longsession">
- <title>拡張セッションと自動バージョニング</title>
-
- <para>
- 1つの <literal>Session</literal> インスタンスとその永続性インスタンスは、
- <emphasis>session-per-conversation</emphasis> として知られる、
- 対話全体で使われます。
- Hibernateはフラッシュする際に、インスタンスのバージョンをチェックします。
- 同時に修正されたことを検出すると、例外を投げます。
- この例外をキャッチして扱うのは、開発者の責任です
- (一般的な選択肢は、変更をマージするか古くないデータでビジネス対話を
- 再スタートする機会をユーザーに提供することです)。
- </para>
-
- <para>
- ユーザーの対話を待っているときは、
- <literal>Session</literal> を基礎となるJDBCコネクションから切り離します。
- このアプローチは、データベースアクセスの中では、最も効率的です。
- アプリケーションは、バージョンチェックや分離されたインスタンスを再追加すること
- に関心を持つ必要はありません。また、あらゆるデータベーストランザクションの中で
- インスタンスを再読み込みする必要はありません。
- </para>
-
- <programlisting><![CDATA[// foo is an instance loaded earlier by the old session
-Transaction t = session.beginTransaction(); // Obtain a new JDBC connection, start transaction
-
-foo.setProperty("bar");
-
-session.flush(); // Only for last transaction in conversation
-t.commit(); // Also return JDBC connection
-session.close(); // Only for last transaction in conversation]]></programlisting>
-
- <para>
- <literal>foo</literal> オブジェクトは、自分をロードした <literal>Session</literal>
- をまだ知っています。
- 古いセッションの上で新しいデータベーストランザクションを開始することで、
- 新しいコネクションを取得し、そのセッションが再開されます。
- データベーストランザクションをコミットすることで、
- セッションからJDBCコネクションを切断し、コネクションをプールに返します。
- 再接続した後、更新していないデータのバージョンチェックを強制するために、
- 他のトランザクションにより更新されているかもしれないオブジェクトに関して、
- <literal>LockMode.READ</literal> をつけて <literal>Session.lock()</literal>
- を呼び出すことができます。
- 更新して <emphasis>いる</emphasis> データをロックする必要はありません。
-
- 通常、拡張 <literal>Session</literal> に <literal>FlushMode.MANUAL</literal>
- をセットします。
- 最後のデータベーストランザクションの周期でのみ、
- 対話の中で変更されたすべてを実際に永続化させるためです。
- ゆえに、最後のデータベーストランザクションのみ <literal>flush()</literal>
- オペレーションを含みます。そして、対話を終わらせるために、
- セッションも <literal>close()</literal> します。
- </para>
-
- <para>
- ユーザーが考慮中に、格納することができないくらい <literal>Session</literal>
- が大きいのであれば、このパターンは問題があります。
- 例えば、<literal>HttpSession</literal> は可能な限り小さく保つべきです。
- <literal>Session</literal> は(強制的に)1次キャッシュでもあり、
- ロードしたオブジェクトをすべて保持します。
- おそらく、リクエスト/レスポンスのサイクルが数回であれば、この戦略が使えます。
-
- 1つの対話のためだけに <literal>Session</literal> を使うべきです。
- なぜなら、すぐに新鮮でないデータを持つためです。
- </para>
-
- <para>
- (Hibernateの以前のバージョンは、明示的な <literal>Session</literal> の
- 切断と再接続が必要だったことに注意してください。
- これらのメソッドは非推奨になりました。
- なぜなら、トランザクションの開始と終了は同じ効果があるためです。)
- </para>
-
- <para>
- 切断した <literal>Session</literal> を永続化層の近くで保持すべきであることに
- 注意してください。
- 言い換えると、3層環境の中で <literal>Session</literal> を保持するために、
- EJBステートフルセッションBeanを使ってください。
- <literal>HttpSession</literal> に格納するために、Web層に転送しないでください
- (別の層へのシリアライズもしないでください)。
- </para>
-
- <para>
- 拡張セッションパターン(もしくは、<emphasis>session-per-conversation</emphasis>)は、
- 自動的なカレントセッションコンテキスト管理を実施するより難しい。
- このために、あなたは <literal>CurrentSessionContext</literal> の実装を供給する必要があります。
- Hibernate Wikiにある例を参照してください。
- </para>
-
- </sect2>
-
- <sect2 id="transactions-optimistic-detached">
- <title>デタッチされたオブジェクトと自動バージョニング</title>
-
- <para>
- 新しい <literal>Session</literal>により、永続化ストア(訳注:DB)との対話が発生します。
- また一方、同じ永続性インスタンスが、データベースとの対話ごとに再利用されます。
- アプリケーションは、元々は他の <literal>Session</literal> でロードされ、
- デタッチされたインスタンスの状態を操作します。
- そして、<literal>Session.update()</literal> もしくは、<literal>Session.saveOrUpdate()</literal>、
- <literal>Session.merge()</literal> を使って、それらのインスタンスを再追加します。
- </para>
-
- <programlisting><![CDATA[// foo is an instance loaded by a previous Session
-foo.setProperty("bar");
-session = factory.openSession();
-Transaction t = session.beginTransaction();
-session.saveOrUpdate(foo); // Use merge() if "foo" might have been loaded already
-t.commit();
-session.close();]]></programlisting>
-
- <para>
- この場合もやはり、Hibernateはフラッシュする際に、インスタンスのバージョンをチェックします。
- 更新の競合が発生した場合には、例外を投げます。
- </para>
-
- <para>
- オブジェクトが修正されていないことを確信している場合は、
- <literal>update()</literal> の代わりに、<literal>LockMode.READ</literal> を使って、
- <literal>lock()</literal> を呼び出すこともできます
- (すべてのキャッシュを迂回し、バージョンチェックを実施します)。
- </para>
-
- </sect2>
-
- <sect2 id="transactions-optimistic-customizing">
- <title>自動バージョニングのカスタマイズ</title>
-
- <para>
- マッピングの <literal>optimistic-lock</literal> 属性に <literal>false</literal>
- を設定することにより、特定のプロパティやコレクションのために
- 自動バージョンインクリメントを無効にできます。
- プロパティがダーティであっても、バージョンをインクリメントしません。
- </para>
-
- <para>
- レガシーのデータベーススキーマは、しばしば固定的であり、変更できません。
- または、他のアプリケーションが同じデータベースにアクセスしなければならず、
- そのアプリケーションはバージョン番号やタイムスタンプさえ操作する方法を知りません。
- どちらの場合も、テーブルの特定のカラムを当てにして、バージョニングを行えません。
- バージョンやタイムスタンプのプロパティをマッピングせずに、バージョンチェックさせるために、
- <literal><class></literal> マッピングに <literal>optimistic-lock="all"</literal> を
- 指定してください。
- 行のすべてのフィールドの状態を比較するようになります。
- これは、Hibernateが古い状態と新しい状態を比較できる場合に、
- 理論的に動作するだけであることに注意してください。
- 例えば、session-per-request-with-detached-objects ではなく、
- 1つの長い <literal>Session</literal> を使う場合です。
- </para>
-
- <para>
- ときどき、行われた変更が重ならない限り、同時に行われた変更を受け入れることができます。
- <literal><class></literal> マッピングに <literal>optimistic-lock="dirty"</literal>
- を設定した場合、フラッシュする際に、Hibernateはダーティフィールドのみを比較します。
- </para>
-
- <para>
- 専用のバージョン/タイムスタンプのカラムを使う場合、
- もしくはすべて/ダーティのフィールドを比較する場合どちらであっても、
- Hibernateはエンティティごとに1つの <literal>UPDATE</literal> 文を
- (適切な <literal>WHERE</literal> 節と共に)使い、
- バージョンチェックと情報の更新を行います。
- 関連するエンティティの再追加をカスケードするために、
- 連鎖的な永続化を使用した場合、不必要な更新を実行するかもしれません。
- これは通常問題になりません。
- しかし、分離したインスタンスを変更していなくとも、
- データベースの <emphasis>on update</emphasis> トリガーが実行されるかもしれません。
- <literal><class></literal> マッピングに
- <literal>select-before-update="true"</literal> を設定することによって、
- この振る舞いをカスタマイズできます。
- 確実に変更されたかを確認するために、行を更新する前に、
- 必ずインスタンスを <literal>SELECT</literal> します。
- </para>
-
- </sect2>
-
- </sect1>
-
- <sect1 id="transactions-locking">
- <title>悲観的ロック</title>
-
- <para>
- ユーザがロック戦略に悩むのに多くの時間を費やすことを意図していません。
- 通常は、JDBCコネクションに分離レベルを指定し、
- 単にデータベースにすべての仕事をさせれば十分です。
- しかしながら、高度なユーザは、排他的な悲観的ロックを獲得することか、
- 新しいトランザクションが開始される際にロックを再獲得することを
- ときどき望むかもしれません。
- </para>
-
- <para>
- Hibernateはいつもデータベースのロックの仕組みを使います。
- メモリ内のオブジェクトを決してロックしません!
- </para>
-
- <para>
- <literal>LockMode</literal> クラスは、Hibernateが獲得できる異なるロックレベルを定義します。
- 以下の仕組みにより、ロックを獲得できます。
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- <literal>LockMode.WRITE</literal> は、
- Hibernateが行を更新もしくは挿入する際に自動的に得られます。
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>LockMode.UPGRADE</literal> は、
- データベースでサポートされている文法 <literal>SELECT ... FOR UPDATE</literal>
- を使った、明示的なユーザー要求により得られるかもしれません。
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>LockMode.UPGRADE_NOWAIT</literal> は、
- Oracle で <literal>SELECT ... FOR UPDATE NOWAIT</literal> を使った、
- 明示的なユーザー要求により得られるかもしれません。
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>LockMode.READ</literal> は、
- Repeatable ReadもしくはSerializableの分離レベルで、データを読んだ際に自動的に得られます。
- おそらく、明示的なユーザー要求により、再取得されます。
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>LockMode.NONE</literal> は、ロックしないことを表します。
- <literal>Transaction</literal> の終わりに、
- すべてのオブジェクトはこのロックモードに切り替わります。
- <literal>update()</literal> や <literal>saveOrUpdate()</literal> を呼び出すことによって、
- セッションに関連付けられたオブジェクトも、このロックモードで出発します。
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- 「明示的なユーザー要求」とは、下記の方法の1つで言い表せます。
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- <literal>LockMode</literal> を指定した <literal>Session.load()</literal> の呼び出し。
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>Session.lock()</literal> の呼び出し。
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>Query.setLockMode()</literal> の呼び出し。
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- <literal>UPGRADE</literal> もしくは <literal>UPGRADE_NOWAIT</literal> が指定された
- <literal>Session.load()</literal> が呼び出され、
- かつ要求されたオブジェクトがセッションによってまだロードされていなかった場合は、
- <literal>SELECT ... FOR UPDATE</literal> を使って、オブジェクトがロードされます。
- <literal>load()</literal> で呼び出されたオブジェクトが、
- 要求されているより制限が少ないロックですでにロードされていた場合は、
- Hibernateはそのオブジェクトのために、<literal>lock()</literal> を呼び出します。
- </para>
-
- <para>
- 指定されたロックモードが <literal>READ</literal> もしくは、<literal>UPGRADE</literal>、
- <literal>UPGRADE_NOWAIT</literal> だった場合、<literal>Session.lock()</literal>
- は、バージョン番号のチェックを実施します。
- (<literal>UPGRADE</literal> もしくは <literal>UPGRADE_NOWAIT</literal> の場合、
- <literal>SELECT ... FOR UPDATE</literal> が使われます。)
- </para>
-
- <para>
- データベースが要求されたロックモードをサポートしていない場合、
- Hibernateは(例外を投げる代わりに、)適切な代わりのモードを使います。
- これは、アプリケーションがポータブルであることを保証します。
- </para>
-
- </sect1>
-
- <sect1 id="transactions-connection-release">
- <title>コネクション開放モード</title>
-
- <para>
- Hibernateのレガシー(2.x)のJDBCコネクション管理に関する振る舞いは、
- 最初に必要とした際に <literal>Session</literal> がコネクションを得るというものでした。
- そして、セッションが閉じられるまで、そのコネクションを保持しました。
- Hibernate 3.xは、セッションにJDBCコネクションをどのように制御するかを伝える
- コネクション開放モードという概念を導入しました。
- 以降の議論は、構成された <literal>ConnectionProvider</literal> を通して提供される
- コネクションに適切であることに注意してください。
- 異なる開放モードは、<literal>org.hibernate.ConnectionReleaseMode</literal> に
- 列挙された値により確認されます。
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- <literal>ON_CLOSE</literal> - 本質的に上記で述べたレガシーの振る舞いです。
- Hibernateセッションは最初にJDBCアクセスを実行する必要がある際にコネクションを得ます。
- そして、セッションが閉じられるまで、コネクションを保持します。
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>AFTER_TRANSACTION</literal> -
- <literal>org.hibernate.Transaction</literal> が完了した後、
- コネクションを開放します。
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>AFTER_STATEMENT</literal> (積極的な開放とも呼ばれる) -
- すべてのステートメントがそれぞれ実行された後、コネクションが開放されます。
- ステートメントがセッションに関連するリソースを開いたままにする場合は、
- この積極的な開放はスキップされます。
- 今のところ、これが起こるのは <literal>org.hibernate.ScrollableResults</literal>
- が使われる場合のみです。
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- コンフィグレーションパラメータの <literal>hibernate.connection.release_mode</literal>
- は、使用する開放モードを指定するために使います。
- 指定できる値は次の通りです。
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- <literal>auto</literal> (デフォルト) - これを選択すると
- <literal>org.hibernate.transaction.TransactionFactory.getDefaultReleaseMode()</literal>
- メソッドによって返される開放モードに委譲されます。
- このメソッドは、
- JTATransactionFactoryにはConnectionReleaseMode.AFTER_STATEMENTを返し、
- JDBCTransactionFactoryにはConnectionReleaseMode.AFTER_TRANSACTIONを返します。
- このデフォルトの振る舞いを変えてうまくいった試しがありません。
- それは、この設定値が原因で起こる障害は、
- ユーザコードの中でバグや間違った条件になりやすいからです。
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>on_close</literal> - ConnectionReleaseMode.ON_CLOSEを使います。
- この設定は後方互換のために残されていますが、使わないことを強く勧めます。
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>after_transaction</literal> - ConnectionReleaseMode.AFTER_TRANSACTIONを使います。
- この設定はJTA環境の中では使うべきではありません。
- ConnectionReleaseMode.AFTER_TRANSACTIONを指定し、自動コミットモードの中では、
- 開放モードがAFTER_STATEMENTであるかのように、コネクションは開放されることに注意してください。
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>after_statement</literal> - ConnectionReleaseMode.AFTER_STATEMENTを使います。
- さらに、設定された <literal>ConnectionProvider</literal> は、
- この設定 (<literal>supportsAggressiveRelease()</literal>) をサポートするかどうか
- を調べるために使用します。
- もしそうでない場合、開放モードはConnectionReleaseMode.AFTER_TRANSACTION
- にリセットされます。
- この設定は次の環境でのみ安全です。
- それは、<literal>ConnectionProvider.getConnection()</literal> を呼び出すたびに
- 基盤となるJDBCコネクションが同じものを取得できるか、
- 同じコネクションが得られることが問題とならない自動コミット環境の中です。
- </para>
- </listitem>
- </itemizedlist>
-
- </sect1>
-
-</chapter>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
+<chapter id="transactions" revision="2">
+ <title>トランザクションと並行性</title>
+
+ <para>
+ Hibernateと同時実行制御について最も重要な点は、容易に理解できることです。
+ Hibernateは新たなロックの振る舞いを追加しておらず、直接JDBCコネクションとJTAリソースを使用します。
+ JDBC、ANSI、およびデータベース管理システム(DBMS)のトランザクション分離の仕様を
+ 少し時間をかけて勉強することを強く推奨します。
+ </para>
+
+ <para>
+ Hibernateはメモリ内のオブジェクトをロックしません。
+ アプリケーションは、データベーストランザクションの分離レベルで
+ 定義した振る舞いを期待できます。
+ トランザクションスコープのキャッシュでもある <literal>Session</literal> のお陰で、
+ 識別子やクエリにより検索したエンティティはリピータブルリードになります
+ (スカラー値を返すようなレポートクエリは違います)。
+ </para>
+
+ <para>
+ バージョニングによる自動的な楽観的同時実行制御に加えて、
+ <literal>SELECT FOR UPDATE</literal> 文を使用して、
+ 行を悲観的ロックするための(マイナーな)APIも提供します。
+ 楽観的同時実行制御とこのAPIについては、この章の後のほうで議論します。
+ </para>
+
+ <para>
+ データベーストランザクションや長い対話(conversation、ロングトランザクション)だけでなく、
+ <literal>Configuration</literal>、<literal>SessionFactory</literal>、および
+ <literal>Session</literal>
+ という粒度でHibernateが行う同時実行制御の議論を始めます。
+ </para>
+
+ <sect1 id="transactions-basics" revision="1">
+ <title>sessionスコープとtransactionスコープ</title>
+
+ <para>
+ <literal>SessionFactory</literal> は生成することが高価で、
+ スレッドセーフなオブジェクトです。
+ よって、アプリケーションのすべてのスレッドで共有すべきです。
+ 通常、アプリケーションの起動時に、
+ <literal>Configuration</literal> インスタンスから1度だけ生成します。
+ </para>
+
+ <para>
+ <literal>Session</literal> は高価ではなく、スレッドセーフなオブジェクトでもありません。
+ よって、1つの要求や1つの対話、1つの作業単位(unit of work)に対して1度だけ使い、
+ その後で捨てるべきです。
+ <literal>Session</literal> は必要になるまで、
+ JDBC <literal>Connection</literal>(もしくは <literal>DataSource</literal>)を獲得しません。
+ ゆえに、実際に使用するときまでリソースを消費しません。
+ </para>
+
+ <para>
+ この状況を完了させるために、 データベーストランザクションについても考えなければなりません。
+ データベース内のロックの競合を少なくするために、
+ データベーストランザクションは可能な限り短くするべきです。
+ 長いデータベーストランザクションは、アプリケーションの高い並列実行性を阻害します。
+ ゆえに、ユーザーが考えている間(作業単位が完了するまで)データベーストランザクションを
+ 開いたままにするのは、たいていの場合よい設計とはいえません。
+ </para>
+
+ <para>
+ 作業単位というスコープとは何でしょうか?
+ 1つのHibernate <literal>Session</literal> は、
+ いくつかのデータベーストランザクションをまたがることができるでしょうか?
+ または、スコープと一対一の関係でしょうか?
+ いつ <literal>Session</literal> を開き、閉じるべきでしょうか?
+ そして、データベーストランザクション境界をどのように分けるのでしょうか?
+ </para>
+
+ <sect2 id="transactions-basics-uow" revision="1">
+ <title>作業単位(Unit of work)</title>
+
+ <para>
+ 1つ目は、<emphasis>session-per-operation</emphasis> アンチパターンを使ってはいけません。
+ すなわち、1つのスレッドの中で、単純なデータベース呼び出しのたびに
+ <literal>Session</literal> を開いて、閉じてはいけません!
+ もちろん、データベーストランザクションについても同様です。
+ アプリケーション中のデータベース呼び出しは、
+ 計画されたシーケンス(planned sequence)を使い、
+ アトミックな作業単位に分類されます。
+ (1つのSQL文ごとにコミットする自動コミットが、
+ 使われないという意味でもあることに注意してください。
+ 自動コミットは、SQLコンソールでアドホックな作業をする際に使うものです。
+ Hibernateは直ちに自動コミットモードを無効にします。
+ もしくは、アプリケーションサーバーが無効化することを期待します。)
+ データベーストランザクションはオプションではありません。
+ データベースとのすべての通信は、データの読み込みであっても、書き込みであっても、
+ トランザクションの中で行わなければなりません。
+ 説明すると、データ読み込みに対して、自動コミットは避けるべきです。
+ なぜなら、多数の小さなトランザクションは、明確に定義された1つの作業単位と比べて、
+ パフォーマンスがよくなることはありません。
+ 後者は保守性や拡張性もよりすぐれています。
+ </para>
+
+ <para>
+ マルチユーザーのクライアント/サーバーアプリケーションの中で、
+ 最もよく使われるパターンは、<emphasis>session-per-request</emphasis> です。
+ このモデルの中では、
+ クライアントから(Hibernate永続化層が動作する)サーバーへリクエストが送られ、
+ 新しいHibernate <literal>Session</literal> が開かれます。
+ そして、この作業単位の中ですべてのデータベース処理が実行されます。
+ 作業が完了した(そして、クライアントへのレスポンスが準備できた)時点で、
+ session をフラッシュし、閉じます。
+ クライアントの要求を処理するために、1つのデータベーストランザクションを使用するでしょう。
+ <literal>Session</literal> を開き、閉じる際に、
+ データベーストランザクションを開始し、コミットします。
+ 二つの関係は一対一です。
+ このモデルは多くのアプリケーションに完全に適合します。
+ </para>
+
+
+
+ <para>
+ 以降の実装にチャレンジしてください。
+ Hibernateは単純なこのパターンのために、予め組み込まれた
+ 「current session」の管理を提供します。
+ サーバーリクエストを処理する際はトランザクションを開始しなければなりません。
+ そして、レスポンスをクライアントに送信する前にトランザクションを終わらせます。
+ 好きな方法で実現できます。一般的な解決策は <literal>ServletFilter</literal> や
+ サービスメソッドをポイントカットしてAOPインターセプター、
+ proxy/interception コンテナです。
+ EJBコンテナはEJBセッションビーンをトランザクション境界として
+ アスペクトをクロスカットする実装の標準的な方法です(CMTによる宣言的)。
+ プログラムによるトランザクション境界を使うと決めた場合、
+ 簡単に使うため、互換性のあるコードにするために、
+ この章の後のほうにあるHibernate <literal>Transaction</literal> APIのほうがよいです。
+ </para>
+
+ <para>
+ アプリケーションのコードは、必要なときにどこでも、何回でも、
+ 単に <literal>sessionFactory.getCurrentSession()</literal> を呼び出すだけで
+ 「現在のセッション」にアクセスできます。
+ 現在のデータベーストランザクションへの <literal>セッション</literal> を常に取得します。
+ リソース・ローカルな環境、もしくはJTA環境を構成しなければなりません
+ (<xref linkend="architecture-current-session"/> を参照してください)。
+ </para>
+
+ <para>
+ ときどき、「ビューを描画する」まで <literal>セッション</literal>
+ とデータベーストランザクションのスコープを拡張すると便利なことがあります。
+ これは、要求の処理と描画のフェーズを分けている
+ サーブレットアプリケーションにおいて特に役立ちます。
+ 独自のインターセプタを実装すれば、
+ ビューを描画するまでデータベーストランザクションを拡張するのは簡単です。
+ しかし、コンテナ管理トランザクションのEJBに頼る場合は、簡単にはできません。
+ なぜなら、ビューの描画を開始する前に、EJBのメソッドがリターンした際に、
+ トランザクションが完了するためです。
+ この <emphasis>Open Session in View</emphasis> パターンに関連するヒントと例については、
+ HibernateのWebサイトやフォーラムを参照してください。
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-basics-apptx" revision="1">
+ <title>長い対話</title>
+
+ <para>
+ session-per-requestパターンは、作業単位を設計する際に役立つ考えというだけではありません。
+ 多くのビジネスプロセスは、ユーザーとの一連の相互作用全体を要求します。
+ その相互作用には、データベースアクセスが含まれます。
+
+ Webとエンタープライズアプリケーションでは、データベーストランザクションが
+ ユーザとの相互作用にまで渡ることは許されません。
+
+ 次の例をよく考えてみてください。
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ ダイアログの最初の画面が開き、個々の <literal>Session</literal>
+ とデータベーストランザクションの中でロードされたデータをユーザーに見せます。
+ ユーザーはオブジェクトを自由に修正できます。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 5分後にユーザーは「Save」をクリックし、修正が永続化されるのを期待します。
+ また、この情報を編集したのは自分1人だけで、
+ 修正のコンフリクトは発生しないと期待します。
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ この作業単位を(ユーザーの視点で)長期の <emphasis>対話</emphasis>
+ (もしくは、<emphasis>アプリケーショントランザクション</emphasis> )と呼びます。
+ アプリケーションにこれを実装する方法はたくさんあります。
+ </para>
+
+ <para>
+ 最初に思いつく実装は、ユーザーが考えている間、<literal>Session</literal>
+ とデータベーストランザクションを開いたままにしておくことです。
+ 同時に修正されず、分離と原子性が保証されるように、
+ データベース内のロックは保持したままにします。
+ もちろん、これはアンチパターンです。
+ なぜなら、ロックの競合が発生すると、
+ アプリケーションが同時ユーザー数に応じてスケールアップできなくなるからです。
+ </para>
+
+ <para>
+ 明らかに、対話を実装するためには、
+ いくつかのデータベーストランザクションを使用するべきです。
+ この場合、ビジネスプロセスの分離を維持することは、
+ アプリケーション層の責務の1つになります。
+ 1つの対話は、
+ 通常いくつかのデータベーストランザクションに及びます。
+ データベーストランザクションの1つのみ(最後の1つ)が更新したデータを保存し、
+ 他はデータを読むだけであれば、それはアトミックです
+ (例えば、いくつかの要求/応答を繰り返すウィザード形式のダイアログ)。
+ これは聞くより、実装したほうが簡単です。
+ Hibernateの機能を使うのであれば、特に簡単です。
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>自動バージョニング</emphasis>
+ - Hibernateは自動的に楽観的同時実行制御ができます。
+ ユーザーが考えている間に同時に修正がおきた場合、自動的に検出できます。
+ 通常、対話の終了時にチェックするだけです。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>分離(Detached)オブジェクト</emphasis> - すでに議論した
+ <emphasis>session-per-request</emphasis> パターンを使うと決定した場合、
+ ロードされたすべてのインスタンスは、ユーザが考えている間は、
+ セッションから分離された状態になります。
+ オブジェクトをセッションに再追加し、修正を永続化できます。
+ これを <emphasis>session-per-request-with-detached-objects</emphasis>
+ パターンと呼びます。
+ 自動バージョニングを使うことで、同時に行われる修正を分離できます。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>拡張(もしくは、長い)セッション</emphasis>
+ - Hibernateの <literal>Session</literal> は、
+ データベーストランザクションをコミットした後、
+ 裏で結びついているJDBCコネクションを切断できます。
+ そして、クライアントからの新しい要求が発生した際に、再接続できます。
+ このパターンは、<emphasis>session-per-conversation</emphasis>
+ という名で知られており、オブジェクトをセッションへ再追加することさえ不要にします。
+ 自動バージョニングを使うことで、同時に行われる修正を分離できます。
+
+ 通常 <literal>Session</literal> を自動的にフラッシュさせず、
+ 明示的にフラッシュします。
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ <emphasis>session-per-request-with-detached-objects</emphasis> と
+ <emphasis>session-per-conversation</emphasis> の2つは、
+ 利点と欠点を持っています。
+ これについては、この章の後のほうで、楽観的同時実行制御の文脈の中で議論します。
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-basics-identity">
+ <title>オブジェクト識別子を考える</title>
+
+ <para>
+ アプリケーションは、2つの異なる <literal>Session</literal> から
+ 同じ永続状態に同時にアクセスできます。
+ しかし、2つの <literal>Session</literal> インスタンスが
+ 永続性クラスの1つのインスタンスを共有することはできません。
+ ゆえに、識別子には2つの異なる概念があるということになります。
+ </para>
+
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term>データベース識別子</term>
+ <listitem>
+ <para>
+ <literal>foo.getId().equals( bar.getId() )</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>JVM識別子</term>
+ <listitem>
+ <para>
+ <literal>foo==bar</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>
+ <emphasis>個々の</emphasis> <literal>Session</literal> に追加されたオブジェクトにとって
+ (すなわち、1つの <literal>Session</literal> のスコープの中では)、2つの概念は同じです。
+ データベース同一性とJVM同一性が一致することを、Hibernateが保証します。
+ しかし、アプリケーションが2つの異なるセッションから
+ 「同じ」(永続性識別子の)ビジネスオブジェクトに同時にアクセスする限り、
+ 2つのインスタンスは実際に(JVM識別子が)「異なり」ます。
+ 楽観的アプローチによって、(自動バージョニングの)フラッシュ/コミット時に
+ コンフリクトが解決されます。
+ </para>
+
+ <para>
+ このアプローチでは、Hibernateとデータベースに同時実行についての心配が残ります。
+ 一方で、最高のスケーラビリティが提供されます。
+ なぜなら、1スレッドの作業単位の中で一意性が保証されれば、
+ 高価なロックや同期化が不要になるためです。
+ <literal>Session</literal> ごとに1つのスレッドを貼り付ける限り、
+ アプリケーションはビジネスオブジェクトをsynchronizeする必要はありません。
+ <literal>Session</literal> 内では、アプリケーションはオブジェクトを比較するために、
+ <literal>==</literal> を安全に使用できます。
+ </para>
+
+ <para>
+ けれども、<literal>Session</literal> の外で <literal>==</literal>
+ を使うアプリケーションは、予期しない結果に遭遇します。
+ これは予期しない場所で起こりえます。
+ 例えば、2つの分離インスタンスを同じ <literal>Set</literal> に
+ putしたときなどです。
+ 両方とも同じデータベース識別子を持ちます(すなわち、同じ行を表します)。
+ しかし、分離状態のインスタンスのJVM識別子は当然保証されません。
+ 開発者は、永続性クラスの <literal>equals()</literal> と <literal>hashCode()</literal>
+ メソッドをオーバーライドし、オブジェクト等価性の概念を実装すべきです。
+ 警告が1つあります。等価性の実装にデータベース識別子を使わないでください。
+ ユニークな(普通は不変の)属性の組み合わせであるビジネスキーを使ってください。
+ もし、一時オブジェクトが永続化された場合、データベース識別子が変わります。
+ 一時オブジェクトを(通常分離インスタンスと共に) <literal>Set</literal>
+ に保持する場合、ハッシュコードが変わるということは、<literal>Set</literal>
+ の契約を破るということです。
+ ビジネスキーのための属性は、データベースの主キーほど安定すべきではないです。
+ オブジェクトが同じ <literal>Set</literal> の中にいる間だけ、安定を保証すべきです。
+ この問題のより徹底的な議論は、HibernateのWebサイトを参照してください。
+ また、これはHibernateの問題ではなく、単にJavaオブジェクトの識別子や等価性を
+ どのように実装すべきかということです。
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-basics-issues">
+ <title>一般的な問題</title>
+
+ <para>
+ <emphasis>session-per-user-session</emphasis> と
+ <emphasis>session-per-application</emphasis> アンチパターン
+ は使ってはいけません(もちろん、まれに例外があります)。
+ 注意:下記の問題のいくつかは、推奨されるパターンとしても出現します。
+ 設計を決定する前に、裏の意味を理解するようにしてください。
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>Session</literal> はスレッドセーフではありません。
+ HTTPリクエスト、セッションBean、Swingワーカーのように、
+ 同時実行が可能なものが <literal>Session</literal> インスタンスを共有すると、
+ 競合状態を引き起こします。
+ (後で議論する)<literal>HttpSession</literal> の中で
+ Hibernate <literal>Session</literal> を保持する場合、
+ HttpSessionへのアクセスを同期化することを考慮すべきです。
+ さもなければ、ユーザーが十分早くリロードをクリックすると、
+ 同時に走る2つのスレッドの中で、同じ <literal>Session</literal> が使われます。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Hibernateが例外を投げた場合は、データベーストランザクションをロールバックし、
+ 直ちに <literal>Session</literal> を閉じるべきです(詳細を後で議論します)。
+ <literal>Session</literal> がアプリケーションに結び付けられているのであれば、
+ アプリケーションを停止すべきです。
+ データベーストランザクションをロールバックしても、ビジネスオブジェクトは
+ トランザクションを開始したときの状態に戻りません。
+ これは、データベースの状態とビジネスオブジェクトは同期していないことを意味します。
+ 通常これは問題になりません。
+ なぜなら、例外は回復できないからです。
+ とにかくロールバックした後にやり直すべきです。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>Session</literal> は永続(persistent)状態のすべてのオブジェクトを
+ キャッシュします(Hibernateは監視し、ダーティ状態かチェックします)。
+ これは、長い間セッションを開いたままにするか、
+ 非常に多くのデータをロードし続けるかした場合は、
+ OutOfMemoryExceptionが発生するまで無限に大きくなることを意味します。
+ 解決策の1つは、<literal>Session</literal> キャッシュを管理するために、
+ <literal>clear()</literal> か <literal>evict()</literal> を呼ぶことです。
+ しかし、大きなデータを処理する必要があるなら、
+ たぶんストアドプロシージャを考慮するべきでしょう。
+ いくつかの解決策は、<xref linkend="batch"/> で紹介されています。
+ ユーザーセッションの間、<literal>Session</literal> を開いたままにするということは、
+ データが新鮮でなくなる確率が高くなることを意味します。
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="transactions-demarcation">
+ <title>データベーストランザクション境界</title>
+
+ <para>
+ データベース(もしくはシステム)トランザクションの境界は、常に必要です。
+ データベーストランザクションの外で、データベースとの通信は起きません
+ (これは自動コミットモードに慣れている多くの開発者を混乱させるかもしれません)。
+ 読み込むだけの操作にでも、いつも明確なトランザクション境界を使用してください。
+ 分離レベルとデータベースの能力次第で、これは必要ないかもしれませんが、
+ 常にトランザクション境界を明示的に指定しても、マイナス面は全くありません。
+
+ 確かに、1つのデータベーストランザクションは多数の小さなトランザクションより
+ (データの読み込みであっても)パフォーマンスがすぐれています。
+ </para>
+
+ <para>
+ J2EE環境に管理されていない状態
+ (すなわち、スタンドアロン、単純なWebやSwingアプリケーション)でも、
+ 管理された状態でも、Hibernateアプリケーションを実行できます。
+ 管理されていない環境では、Hiberanteがデータベースのコネクションプールを提供します。
+ アプリケーション開発者は、トランザクション境界を手動で設定しなければなりません。
+ 言い換えると、データベーストランザクションの開始、コミット、ロールバックを
+ 開発者自身が設定する必要があるということです。
+
+ 通常、管理された環境では、コンテナ管理によるトランザクション(CMT)が提供されます。
+ 例えば、セッションBeanのデプロイメントディスクリプタで宣言的に定義し、
+ トランザクションを組み立てます。
+ プログラムによるトランザクション境界はもう必要ありません。
+ </para>
+
+ <para>
+ しかしながら、管理されていないリソース・ローカルな環境と
+ JTAに依存したシステム(CMTではなくBMT)の両方に、
+ 永続化層をポータブルに保つのは、しばしば望ましいことです。
+
+ デプロイ環境のネイティブのトランザクションシステムを呼び出す
+ <literal>Transaction</literal> というラッパーAPIをHibernateが提供します。
+ このAPIを使うかは任意ですが、CMTのセッションBeanを使わないのであれば、使うことを強く推奨します。
+ </para>
+
+ <para>
+ 通常、<literal>Session</literal> 終了は、4つの異なるフェーズを含みます。
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ セッションのフラッシュ
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ トランザクションのコミット
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ セッションのクローズ
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 例外のハンドリング
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ セッションのフラッシュについては、前のほうですでに議論しました。
+ 管理された環境と管理されていない環境の両方について、
+ トランザクション境界と例外ハンドリングをもっと詳しく見ていきましょう。
+ </para>
+
+
+ <sect2 id="transactions-demarcation-nonmanaged" revision="2">
+ <title>管理されていない環境</title>
+
+ <para>
+ Hibernate永続化層を管理されていない環境で実装する場合は、
+
+ 通常単純なコネクションプール(すなわちDataSourceではない)によって、
+ データベースコネクションを制御します。
+ Hibernateはそのコネクションプールから必要なコネクションを取得します。
+
+ セッション/トランザクション制御のイディオムは次のようになります。
+ </para>
+
+ <programlisting><![CDATA[// Non-managed environment idiom
+Session sess = factory.openSession();
+Transaction tx = null;
+try {
+ tx = sess.beginTransaction();
+
+ // do some work
+ ...
+
+ tx.commit();
+}
+catch (RuntimeException e) {
+ if (tx != null) tx.rollback();
+ throw e; // or display error message
+}
+finally {
+ sess.close();
+}]]></programlisting>
+
+ <para>
+ 明示的に <literal>Session</literal> の <literal>flush()</literal> を呼び出すべきではなく、
+ <literal>commit()</literal> を呼び出すことにより、自動的に同期化処理が実行されます
+ (セッションの <xref linkend="objectstate-flushing">FlushMode</xref> に依存している)。
+
+ <literal>close()</literal> を呼び出すことにより、セッションの終わりを明確にします。
+ <literal>close()</literal> が暗黙的に行う主なことは、
+ セッションがJDBCコネクションを開放することです。
+
+ 上記のJavaコードはポータブルであり、管理されていない環境とJTA環境の両方で実行できます。
+ </para>
+
+ <para>
+ より適応性のある解決策は、Hibernateに予め組み込まれている
+ 「current session」コンテキスト管理です。
+ 言葉で説明するより下記を見たほうが速いでしょう。
+ </para>
+
+ <programlisting><![CDATA[// Non-managed environment idiom with getCurrentSession()
+try {
+ factory.getCurrentSession().beginTransaction();
+
+ // do some work
+ ...
+
+ factory.getCurrentSession().getTransaction().commit();
+}
+catch (RuntimeException e) {
+ factory.getCurrentSession().getTransaction().rollback();
+ throw e; // or display error message
+}]]></programlisting>
+
+ <para>
+ 正規のアプリケーションの中では、このようなコードの切れ端を決して見ないでしょう。
+ 致命的な(システム)例外は、常に「最上位」でキャッチすべきです。
+ 言い換えれば、(永続化層で)Hibernate呼び出しを実行するコードと、
+ <literal>RuntimeException</literal> を制御する
+ (通常はクリーンアップと終了のみ行うことができる)コードは、別々の層の中にあります。
+ Hibernateによるカレントコンテキスト管理は、この設計をかなり単純にします。
+ 必要なのは、<literal>SessionFactory</literal> にアクセスすることだけです。
+ 例外処理は、この章の後のほうで議論します。
+ </para>
+
+ <para>
+ 注意:(デフォルトですが)
+ <literal>org.hibernate.transaction.JDBCTransactionFactory</literal>
+ を選択するべきです。
+ 第2の用例としては、
+ <literal>hibernate.current_session_context_class</literal> を
+ <literal>"thread"</literal> とするとよいでしょう。
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-demarcation-jta" revision="3">
+ <title>JTAを使用する</title>
+
+ <para>
+ 永続化層をアプリケーションサーバー(例えば、EJBセッションBeanの背後)で実行する場合、
+ Hibernateから取得するすべてのデータソースコネクションは、
+ 自動的にグローバルJTAトランザクションの一部になります。
+
+ EJBを使わずに、スタンドアロンのJTA実装を導入することもできます。
+ JTA統合のために、Hibernateは2つの戦略を提供します。
+ </para>
+
+ <para>
+ Bean管理トランザクション(BMT)を使い、<literal>Transaction</literal> APIを使う場合、
+ HibernateはアプリケーションサーバーにBMTトランザクションの開始と終わりを告げます。
+ すなわち、トランザクション管理のコードは、管理されない環境と同じになります。
+ </para>
+
+ <programlisting><![CDATA[// BMT idiom
+Session sess = factory.openSession();
+Transaction tx = null;
+try {
+ tx = sess.beginTransaction();
+
+ // do some work
+ ...
+
+ tx.commit();
+}
+catch (RuntimeException e) {
+ if (tx != null) tx.rollback();
+ throw e; // or display error message
+}
+finally {
+ sess.close();
+}]]></programlisting>
+
+ <para>
+ トランザクション境界として <literal>Session</literal> を使いたい場合、
+ 簡単にコンテキストを伝播する機能である <literal>getCurrentSession()</literal> があるので、
+ JTAの <literal>UserTransaction</literal> APIを直接使用すべきでしょう。
+ </para>
+
+ <programlisting><![CDATA[// BMT idiom with getCurrentSession()
+try {
+ UserTransaction tx = (UserTransaction)new InitialContext()
+ .lookup("java:comp/UserTransaction");
+
+ tx.begin();
+
+ // Do some work on Session bound to transaction
+ factory.getCurrentSession().load(...);
+ factory.getCurrentSession().persist(...);
+
+ tx.commit();
+}
+catch (RuntimeException e) {
+ tx.rollback();
+ throw e; // or display error message
+}]]></programlisting>
+
+ <para>
+ CMTでは、トランザクション境界をセッションBeanのデプロイメントディスクリプタで定義し、
+ プログラムでは行いません。
+ ゆえに、コードは次のように少なくなります。
+ </para>
+
+ <programlisting><![CDATA[// CMT idiom
+ Session sess = factory.getCurrentSession();
+
+ // do some work
+ ...
+]]></programlisting>
+
+ <para>
+ CMT/EJBの中では、常にロールバックが自動的に実施されます。
+ なぜなら、セッションビーンのメソッドにより投げられた制御されていない
+ <literal>RuntimeException</literal> は、グローバルトランザクションを
+ ロールバックするようにコンテナに伝えるためです。
+ <emphasis>これは、BMTもしくはCMTといっしょにHibernate <literal>Transaction</literal>
+ APIを使う必要は少しもないという意味です。</emphasis>
+ </para>
+
+ <para>
+ Hibernateのトランザクションファクトリを設定する際に、
+ JTAを直接使う(BMTの)場合は <literal>org.hibernate.transaction.JTATransactionFactory</literal> を、
+ CMTセッションビーンの中では <literal>org.hibernate.transaction.CMTTransactionFactory</literal> を
+ 選択すべきだということに注意してください。
+ <literal>hibernate.transaction.manager_lookup_class</literal>
+ をセットすることも思い出してください。
+ なお、<literal>hibernate.current_session_context_class</literal> は、
+ セットしないか(後方互換)、<literal>"jta"</literal> をセットしてください。
+ </para>
+
+ <para>
+ <literal>getCurrentSession()</literal> オペレーションは、JTA環境では1つの欠点を持ちます。
+
+ デフォルトで使われる <literal>after_statement</literal> コネクションリリースモードを使用する上で、
+ 警告が1つあります。
+
+ JTA仕様の愚かな制約のために、
+ <literal>scroll()</literal> または <literal>iterate()</literal> が返した、
+ 閉じられていない <literal>ScrollableResults</literal> または <literal>Iterator</literal>
+ インスタンスをHibernateが自動的にクリーンアップすることはできません。
+
+ <literal>finally</literal> ブロックの中で、
+ <literal>ScrollableResults.close()</literal> または
+ <literal>Hibernate.close(Iterator)</literal> を明示的に呼び出して、
+ 裏に潜んだデータベースカーソルを解放 <emphasis>しなければなりません</emphasis>。
+
+ (もちろん、多くのアプリケーションでは、JTAかCMTコードで <literal>scroll()</literal>
+ や <literal>iterate()</literal> の使用を避けるのは容易です。)
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-demarcation-exceptions">
+ <title>例外ハンドリング</title>
+
+ <para>
+ <literal>Session</literal> が例外(<literal>SQLException</literal>を含む)を投げた場合、
+ 直ちに、データベーストランザクションをロールバックし、<literal>Session.close()</literal>
+ を呼び、<literal>Session</literal> インスタンスを破棄すべきです。
+ <literal>Session</literal> のいくつかのメソッドは、
+ セッションの状態を <emphasis>矛盾したまま</emphasis> にします。
+ Hibernateが投げた例外を、回復できるものとして扱うことはできません。
+ <literal>finally</literal> ブロックの中で <literal>close()</literal> を呼んで、
+ <literal>Session</literal> を確実に閉じてください。
+ </para>
+
+ <para>
+ <literal>HibernateException</literal> は、Hibernate永続化層の中で発生する多くのエラーを
+ ラップする、検査されない例外です(Hibernateの古いバージョンは違いました)。
+ 私たちの意見は、アプリケーション開発者に回復不可能な例外を
+ 下層でキャッチすることを強要すべきではないということです。
+ 多くのシステムでは、検査されない例外と致命的な例外は、
+ コールスタックの最初のフレームの1つ(例えば、最上位の層で)でハンドリングし、
+ エラーメッセージをアプリケーションユーザーに表示します
+ (もしくは、他の適切な処理を実施します)。
+ Hibernateは、<literal>HibernateException</literal> 以外の検査されない例外も
+ 投げることに注意してください。
+ これらもまた、回復不可能であり、適切な処理を実施すべきです。
+ </para>
+
+ <para>
+ Hibernateは、データベースとの対話中に投げられた <literal>SQLException</literal> を
+ <literal>JDBCException</literal> でラップします。
+ 実は、例外をより意味のある <literal>JDBCException</literal> のサブクラスに
+ 変換しようと試みます。
+ 元の <literal>SQLException</literal> は、<literal>JDBCException.getCause()</literal>
+ によりいつでも得られます。
+ Hibernateは、<literal>SessionFactory</literal> に追加されている
+ <literal>SQLExceptionConverter</literal> を使い、<literal>SQLException</literal> を
+ 適当な <literal>JDBCException</literal> サブクラスに変換します。
+ デフォルトでは、<literal>SQLExceptionConverter</literal> は設定されているSQL方言により
+ 定義されます。
+ 一方で、独自の実装に差し替えることもできます
+ (詳細は、<literal>SQLExceptionConverterFactory</literal> クラスのJavadocを参照してください)。
+ 標準的な <literal>JDBCException</literal> のサブタイプを下記に示します。
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>JDBCConnectionException</literal> -
+ 基礎となるJDBC通信のエラーを表します。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>SQLGrammarException</literal> -
+ 発行するSQLの文法もしくは構文の問題を表します。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ConstraintViolationException</literal> -
+ 何らかの形式の完全性制約違反を表します。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockAcquisitionException</literal> -
+ 要求された操作を実施するのに必要なロックレベルを得る際のエラーを表します。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>GenericJDBCException</literal> -
+ 他のカテゴリに一致しなかった一般的な例外です。
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect2>
+
+ <sect2 id="transactions-demarcation-timeout">
+ <title>トランザクションのタイムアウト</title>
+
+ <para>
+ EJBのような管理された環境が提供するきわめて重要な特徴の1つは、
+ トランザクションのタイムアウトです。
+ これは管理されていないコードには提供できません。
+ トランザクションタイムアウトは、不品行なトランザクションが
+ ユーザーにレスポンスを返さないまま、無期限にリソースを使い続けない
+ ことを保障します。
+ 管理された環境(JTA)の外では、Hibernateはこの機能をフルに提供できません。
+ しかしながら、Hibernateは次のようなデータアクセス操作の制御くらいはできます。
+ データベースレベルのデッドロックや大きなリザルトセットを返すクエリを
+ 定義されたタイムアウトによって確実に制限します。
+ 管理された環境では、HibernateはトランザクションタイムアウトをJTAに委譲します。
+ この機能は、Hibernateの <literal>Transaction</literal> オブジェクトに
+ よって抽象化されています。
+ </para>
+
+ <programlisting><![CDATA[
+Session sess = factory.openSession();
+try {
+ //set transaction timeout to 3 seconds
+ sess.getTransaction().setTimeout(3);
+ sess.getTransaction().begin();
+
+ // do some work
+ ...
+
+ sess.getTransaction().commit()
+}
+catch (RuntimeException e) {
+ sess.getTransaction().rollback();
+ throw e; // or display error message
+}
+finally {
+ sess.close();
+}]]></programlisting>
+
+ <para>
+ CMTビーンの中では <literal>setTimeout()</literal> を
+ 呼び出せないことに注意してください。
+ トランザクションタイムアウトは宣言的に定義されるべきです。
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="transactions-optimistic">
+ <title>楽観的同時実行制御</title>
+
+ <para>
+ 高い並列性と高いスケーラビリティの両方を実現するアプローチは、
+ バージョニングを使った楽観的同時実行制御のみです。
+ 更新の衝突を見つけるために(および、更新が失われるのを防ぐために)、
+ バージョン番号もしくはタイムスタンプを使って、バージョンをチェックします。
+ Hibernateは、楽観的同時実行を行うアプリケーションコードを書くための
+ アプローチを3つ提供します。
+ 私たちが見せるユースケースは、長い対話を持ちますが、
+ バージョンチェックはまだ1つのデータベーストランザクションの中で更新を失うことを防ぐ
+ 利点も持っています。
+ </para>
+
+ <sect2 id="transactions-optimistic-manual">
+ <title>アプリケーションによるバージョンチェック</title>
+
+ <para>
+ Hibernateにほとんど助けてもらわずに実装するケースです。
+ データベースとのやり取りは、それぞれ新しい <literal>Session</literal> の中で起こります。
+ 開発者は、すべての永続性インスタンスを操作する前に、
+ データベースから再読み込みする責務があります。
+ このアプローチでは、対話トランザクションの分離を守るために、
+ アプリケーション自身がバージョンチェックを行う必要があります。
+ このアプローチは、データベースアクセスの中では、最も非効率です。
+ エンティティEJBと最も似ているアプローチです。
+ </para>
+
+ <programlisting><![CDATA[// foo is an instance loaded by a previous Session
+session = factory.openSession();
+Transaction t = session.beginTransaction();
+
+int oldVersion = foo.getVersion();
+session.load( foo, foo.getKey() ); // load the current state
+if ( oldVersion != foo.getVersion() ) throw new StaleObjectStateException();
+foo.setProperty("bar");
+
+t.commit();
+session.close();]]></programlisting>
+
+ <para>
+ <literal><version></literal> を使って、<literal>version</literal>
+ プロパティをマッピングします。
+ Hibernateは、エンティティがダーティである場合、フラッシュし、
+ その間に <literal>version</literal> プロパティを自動的にインクリメントします。
+ </para>
+
+ <para>
+ もちろん、データの並列性が低い環境で運用しており、バージョンチェックが不要なら、
+ このアプローチを使い、バージョンチェックをスキップするだけです。
+ その場合は、長い対話には、
+ <emphasis>「最後にコミットしたものが勝つ」</emphasis> がデフォルトの戦略でしょう。
+ このアプローチは、アプリケーションのユーザーを混乱させるかもしれないことを
+ 心に留めて置いてください。それは、エラーメッセージや競合した変更をマージする機会が
+ ないまま、更新を失う経験をするためです。
+ </para>
+
+ <para>
+ 確かに、マニュアルによるバージョンチェックは、些細な儀式だけで実行できますが、
+ 多くのアプリケーションにとって実用的ではありません。
+ しばしば、1つのインスタンスだけでなく、
+ 修正されたオブジェクトの完全なグラフをチェックしなければなりません。
+ Hibernateは、設計パラダイムとして、拡張 <literal>Session</literal> か
+ 分離されたインスタンスを自動的にバージョンチェックします。
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-optimistic-longsession">
+ <title>拡張セッションと自動バージョニング</title>
+
+ <para>
+ 1つの <literal>Session</literal> インスタンスとその永続性インスタンスは、
+ <emphasis>session-per-conversation</emphasis> として知られる、
+ 対話全体で使われます。
+ Hibernateはフラッシュする際に、インスタンスのバージョンをチェックします。
+ 同時に修正されたことを検出すると、例外を投げます。
+ この例外をキャッチして扱うのは、開発者の責任です
+ (一般的な選択肢は、変更をマージするか古くないデータでビジネス対話を
+ 再スタートする機会をユーザーに提供することです)。
+ </para>
+
+ <para>
+ ユーザーの対話を待っているときは、
+ <literal>Session</literal> を基礎となるJDBCコネクションから切り離します。
+ このアプローチは、データベースアクセスの中では、最も効率的です。
+ アプリケーションは、バージョンチェックや分離されたインスタンスを再追加すること
+ に関心を持つ必要はありません。また、あらゆるデータベーストランザクションの中で
+ インスタンスを再読み込みする必要はありません。
+ </para>
+
+ <programlisting><![CDATA[// foo is an instance loaded earlier by the old session
+Transaction t = session.beginTransaction(); // Obtain a new JDBC connection, start transaction
+
+foo.setProperty("bar");
+
+session.flush(); // Only for last transaction in conversation
+t.commit(); // Also return JDBC connection
+session.close(); // Only for last transaction in conversation]]></programlisting>
+
+ <para>
+ <literal>foo</literal> オブジェクトは、自分をロードした <literal>Session</literal>
+ をまだ知っています。
+ 古いセッションの上で新しいデータベーストランザクションを開始することで、
+ 新しいコネクションを取得し、そのセッションが再開されます。
+ データベーストランザクションをコミットすることで、
+ セッションからJDBCコネクションを切断し、コネクションをプールに返します。
+ 再接続した後、更新していないデータのバージョンチェックを強制するために、
+ 他のトランザクションにより更新されているかもしれないオブジェクトに関して、
+ <literal>LockMode.READ</literal> をつけて <literal>Session.lock()</literal>
+ を呼び出すことができます。
+ 更新して <emphasis>いる</emphasis> データをロックする必要はありません。
+
+ 通常、拡張 <literal>Session</literal> に <literal>FlushMode.MANUAL</literal>
+ をセットします。
+ 最後のデータベーストランザクションの周期でのみ、
+ 対話の中で変更されたすべてを実際に永続化させるためです。
+ ゆえに、最後のデータベーストランザクションのみ <literal>flush()</literal>
+ オペレーションを含みます。そして、対話を終わらせるために、
+ セッションも <literal>close()</literal> します。
+ </para>
+
+ <para>
+ ユーザーが考慮中に、格納することができないくらい <literal>Session</literal>
+ が大きいのであれば、このパターンは問題があります。
+ 例えば、<literal>HttpSession</literal> は可能な限り小さく保つべきです。
+ <literal>Session</literal> は(強制的に)1次キャッシュでもあり、
+ ロードしたオブジェクトをすべて保持します。
+ おそらく、リクエスト/レスポンスのサイクルが数回であれば、この戦略が使えます。
+
+ 1つの対話のためだけに <literal>Session</literal> を使うべきです。
+ なぜなら、すぐに新鮮でないデータを持つためです。
+ </para>
+
+ <para>
+ (Hibernateの以前のバージョンは、明示的な <literal>Session</literal> の
+ 切断と再接続が必要だったことに注意してください。
+ これらのメソッドは非推奨になりました。
+ なぜなら、トランザクションの開始と終了は同じ効果があるためです。)
+ </para>
+
+ <para>
+ 切断した <literal>Session</literal> を永続化層の近くで保持すべきであることに
+ 注意してください。
+ 言い換えると、3層環境の中で <literal>Session</literal> を保持するために、
+ EJBステートフルセッションBeanを使ってください。
+ <literal>HttpSession</literal> に格納するために、Web層に転送しないでください
+ (別の層へのシリアライズもしないでください)。
+ </para>
+
+ <para>
+ 拡張セッションパターン(もしくは、<emphasis>session-per-conversation</emphasis>)は、
+ 自動的なカレントセッションコンテキスト管理を実施するより難しい。
+ このために、あなたは <literal>CurrentSessionContext</literal> の実装を供給する必要があります。
+ Hibernate Wikiにある例を参照してください。
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-optimistic-detached">
+ <title>デタッチされたオブジェクトと自動バージョニング</title>
+
+ <para>
+ 新しい <literal>Session</literal>により、永続化ストア(訳注:DB)との対話が発生します。
+ また一方、同じ永続性インスタンスが、データベースとの対話ごとに再利用されます。
+ アプリケーションは、元々は他の <literal>Session</literal> でロードされ、
+ デタッチされたインスタンスの状態を操作します。
+ そして、<literal>Session.update()</literal> もしくは、<literal>Session.saveOrUpdate()</literal>、
+ <literal>Session.merge()</literal> を使って、それらのインスタンスを再追加します。
+ </para>
+
+ <programlisting><![CDATA[// foo is an instance loaded by a previous Session
+foo.setProperty("bar");
+session = factory.openSession();
+Transaction t = session.beginTransaction();
+session.saveOrUpdate(foo); // Use merge() if "foo" might have been loaded already
+t.commit();
+session.close();]]></programlisting>
+
+ <para>
+ この場合もやはり、Hibernateはフラッシュする際に、インスタンスのバージョンをチェックします。
+ 更新の競合が発生した場合には、例外を投げます。
+ </para>
+
+ <para>
+ オブジェクトが修正されていないことを確信している場合は、
+ <literal>update()</literal> の代わりに、<literal>LockMode.READ</literal> を使って、
+ <literal>lock()</literal> を呼び出すこともできます
+ (すべてのキャッシュを迂回し、バージョンチェックを実施します)。
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-optimistic-customizing">
+ <title>自動バージョニングのカスタマイズ</title>
+
+ <para>
+ マッピングの <literal>optimistic-lock</literal> 属性に <literal>false</literal>
+ を設定することにより、特定のプロパティやコレクションのために
+ 自動バージョンインクリメントを無効にできます。
+ プロパティがダーティであっても、バージョンをインクリメントしません。
+ </para>
+
+ <para>
+ レガシーのデータベーススキーマは、しばしば固定的であり、変更できません。
+ または、他のアプリケーションが同じデータベースにアクセスしなければならず、
+ そのアプリケーションはバージョン番号やタイムスタンプさえ操作する方法を知りません。
+ どちらの場合も、テーブルの特定のカラムを当てにして、バージョニングを行えません。
+ バージョンやタイムスタンプのプロパティをマッピングせずに、バージョンチェックさせるために、
+ <literal><class></literal> マッピングに <literal>optimistic-lock="all"</literal> を
+ 指定してください。
+ 行のすべてのフィールドの状態を比較するようになります。
+ これは、Hibernateが古い状態と新しい状態を比較できる場合に、
+ 理論的に動作するだけであることに注意してください。
+ 例えば、session-per-request-with-detached-objects ではなく、
+ 1つの長い <literal>Session</literal> を使う場合です。
+ </para>
+
+ <para>
+ ときどき、行われた変更が重ならない限り、同時に行われた変更を受け入れることができます。
+ <literal><class></literal> マッピングに <literal>optimistic-lock="dirty"</literal>
+ を設定した場合、フラッシュする際に、Hibernateはダーティフィールドのみを比較します。
+ </para>
+
+ <para>
+ 専用のバージョン/タイムスタンプのカラムを使う場合、
+ もしくはすべて/ダーティのフィールドを比較する場合どちらであっても、
+ Hibernateはエンティティごとに1つの <literal>UPDATE</literal> 文を
+ (適切な <literal>WHERE</literal> 節と共に)使い、
+ バージョンチェックと情報の更新を行います。
+ 関連するエンティティの再追加をカスケードするために、
+ 連鎖的な永続化を使用した場合、不必要な更新を実行するかもしれません。
+ これは通常問題になりません。
+ しかし、分離したインスタンスを変更していなくとも、
+ データベースの <emphasis>on update</emphasis> トリガーが実行されるかもしれません。
+ <literal><class></literal> マッピングに
+ <literal>select-before-update="true"</literal> を設定することによって、
+ この振る舞いをカスタマイズできます。
+ 確実に変更されたかを確認するために、行を更新する前に、
+ 必ずインスタンスを <literal>SELECT</literal> します。
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="transactions-locking">
+ <title>悲観的ロック</title>
+
+ <para>
+ ユーザがロック戦略に悩むのに多くの時間を費やすことを意図していません。
+ 通常は、JDBCコネクションに分離レベルを指定し、
+ 単にデータベースにすべての仕事をさせれば十分です。
+ しかしながら、高度なユーザは、排他的な悲観的ロックを獲得することか、
+ 新しいトランザクションが開始される際にロックを再獲得することを
+ ときどき望むかもしれません。
+ </para>
+
+ <para>
+ Hibernateはいつもデータベースのロックの仕組みを使います。
+ メモリ内のオブジェクトを決してロックしません!
+ </para>
+
+ <para>
+ <literal>LockMode</literal> クラスは、Hibernateが獲得できる異なるロックレベルを定義します。
+ 以下の仕組みにより、ロックを獲得できます。
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>LockMode.WRITE</literal> は、
+ Hibernateが行を更新もしくは挿入する際に自動的に得られます。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockMode.UPGRADE</literal> は、
+ データベースでサポートされている文法 <literal>SELECT ... FOR UPDATE</literal>
+ を使った、明示的なユーザー要求により得られるかもしれません。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockMode.UPGRADE_NOWAIT</literal> は、
+ Oracle で <literal>SELECT ... FOR UPDATE NOWAIT</literal> を使った、
+ 明示的なユーザー要求により得られるかもしれません。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockMode.READ</literal> は、
+ Repeatable ReadもしくはSerializableの分離レベルで、データを読んだ際に自動的に得られます。
+ おそらく、明示的なユーザー要求により、再取得されます。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockMode.NONE</literal> は、ロックしないことを表します。
+ <literal>Transaction</literal> の終わりに、
+ すべてのオブジェクトはこのロックモードに切り替わります。
+ <literal>update()</literal> や <literal>saveOrUpdate()</literal> を呼び出すことによって、
+ セッションに関連付けられたオブジェクトも、このロックモードで出発します。
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ 「明示的なユーザー要求」とは、下記の方法の1つで言い表せます。
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>LockMode</literal> を指定した <literal>Session.load()</literal> の呼び出し。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>Session.lock()</literal> の呼び出し。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>Query.setLockMode()</literal> の呼び出し。
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ <literal>UPGRADE</literal> もしくは <literal>UPGRADE_NOWAIT</literal> が指定された
+ <literal>Session.load()</literal> が呼び出され、
+ かつ要求されたオブジェクトがセッションによってまだロードされていなかった場合は、
+ <literal>SELECT ... FOR UPDATE</literal> を使って、オブジェクトがロードされます。
+ <literal>load()</literal> で呼び出されたオブジェクトが、
+ 要求されているより制限が少ないロックですでにロードされていた場合は、
+ Hibernateはそのオブジェクトのために、<literal>lock()</literal> を呼び出します。
+ </para>
+
+ <para>
+ 指定されたロックモードが <literal>READ</literal> もしくは、<literal>UPGRADE</literal>、
+ <literal>UPGRADE_NOWAIT</literal> だった場合、<literal>Session.lock()</literal>
+ は、バージョン番号のチェックを実施します。
+ (<literal>UPGRADE</literal> もしくは <literal>UPGRADE_NOWAIT</literal> の場合、
+ <literal>SELECT ... FOR UPDATE</literal> が使われます。)
+ </para>
+
+ <para>
+ データベースが要求されたロックモードをサポートしていない場合、
+ Hibernateは(例外を投げる代わりに、)適切な代わりのモードを使います。
+ これは、アプリケーションがポータブルであることを保証します。
+ </para>
+
+ </sect1>
+
+ <sect1 id="transactions-connection-release">
+ <title>コネクション開放モード</title>
+
+ <para>
+ Hibernateのレガシー(2.x)のJDBCコネクション管理に関する振る舞いは、
+ 最初に必要とした際に <literal>Session</literal> がコネクションを得るというものでした。
+ そして、セッションが閉じられるまで、そのコネクションを保持しました。
+ Hibernate 3.xは、セッションにJDBCコネクションをどのように制御するかを伝える
+ コネクション開放モードという概念を導入しました。
+ 以降の議論は、構成された <literal>ConnectionProvider</literal> を通して提供される
+ コネクションに適切であることに注意してください。
+ 異なる開放モードは、<literal>org.hibernate.ConnectionReleaseMode</literal> に
+ 列挙された値により確認されます。
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>ON_CLOSE</literal> - 本質的に上記で述べたレガシーの振る舞いです。
+ Hibernateセッションは最初にJDBCアクセスを実行する必要がある際にコネクションを得ます。
+ そして、セッションが閉じられるまで、コネクションを保持します。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>AFTER_TRANSACTION</literal> -
+ <literal>org.hibernate.Transaction</literal> が完了した後、
+ コネクションを開放します。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>AFTER_STATEMENT</literal> (積極的な開放とも呼ばれる) -
+ すべてのステートメントがそれぞれ実行された後、コネクションが開放されます。
+ ステートメントがセッションに関連するリソースを開いたままにする場合は、
+ この積極的な開放はスキップされます。
+ 今のところ、これが起こるのは <literal>org.hibernate.ScrollableResults</literal>
+ が使われる場合のみです。
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ コンフィグレーションパラメータの <literal>hibernate.connection.release_mode</literal>
+ は、使用する開放モードを指定するために使います。
+ 指定できる値は次の通りです。
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>auto</literal> (デフォルト) - これを選択すると
+ <literal>org.hibernate.transaction.TransactionFactory.getDefaultReleaseMode()</literal>
+ メソッドによって返される開放モードに委譲されます。
+ このメソッドは、
+ JTATransactionFactoryにはConnectionReleaseMode.AFTER_STATEMENTを返し、
+ JDBCTransactionFactoryにはConnectionReleaseMode.AFTER_TRANSACTIONを返します。
+ このデフォルトの振る舞いを変えてうまくいった試しがありません。
+ それは、この設定値が原因で起こる障害は、
+ ユーザコードの中でバグや間違った条件になりやすいからです。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>on_close</literal> - ConnectionReleaseMode.ON_CLOSEを使います。
+ この設定は後方互換のために残されていますが、使わないことを強く勧めます。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>after_transaction</literal> - ConnectionReleaseMode.AFTER_TRANSACTIONを使います。
+ この設定はJTA環境の中では使うべきではありません。
+ ConnectionReleaseMode.AFTER_TRANSACTIONを指定し、自動コミットモードの中では、
+ 開放モードがAFTER_STATEMENTであるかのように、コネクションは開放されることに注意してください。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>after_statement</literal> - ConnectionReleaseMode.AFTER_STATEMENTを使います。
+ さらに、設定された <literal>ConnectionProvider</literal> は、
+ この設定 (<literal>supportsAggressiveRelease()</literal>) をサポートするかどうか
+ を調べるために使用します。
+ もしそうでない場合、開放モードはConnectionReleaseMode.AFTER_TRANSACTION
+ にリセットされます。
+ この設定は次の環境でのみ安全です。
+ それは、<literal>ConnectionProvider.getConnection()</literal> を呼び出すたびに
+ 基盤となるJDBCコネクションが同じものを取得できるか、
+ 同じコネクションが得られることが問題とならない自動コミット環境の中です。
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect1>
+
+</chapter>
Modified: core/trunk/documentation/manual/ja-JP/src/main/docbook/content/tutorial.xml
===================================================================
--- core/trunk/documentation/manual/ja-JP/src/main/docbook/content/tutorial.xml 2007-10-25 06:31:49 UTC (rev 14130)
+++ core/trunk/documentation/manual/ja-JP/src/main/docbook/content/tutorial.xml 2007-10-25 07:54:59 UTC (rev 14131)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
<chapter id="tutorial">
<title>Hibernateの導入</title>
@@ -692,6 +692,8 @@
<literal>hibernate.cfg.xml</literal> のこの機能の設定で、"thread"を指定したことを思い出してください。
このため現在の作業単位のスコープは、このアプリケーションを実行する現在のJavaスレッドです。
しかしこれで全てではありません。
+ </para>
+ <para>
<literal>Session</literal> は最初に必要となったとき、つまり最初に <literal>getCurrentSession()</literal> が
呼ばれたときに開始します。
そのときHibernateにより現在のスレッドに結び付けられます。
@@ -701,7 +703,16 @@
新しい <literal>Session</literal> を取得して新しい作業単位をスタートできます。
この <emphasis>thread-bound</emphasis> プログラミング・モデルはHibernateを利用する上で最も人気があります。
</para>
-
+ <para>
+ Related to the unit of work scope, should the Hibernate <literal>Session</literal> be used to
+ execute one or several database operations? The above example uses one <literal>Session</literal>
+ for one operation. This is pure coincidence, the example is just not complex enough to show any
+ other approach. The scope of a Hibernate <literal>Session</literal> is flexible but you should
+ never design your application to use a new Hibernate <literal>Session</literal> for
+ <emphasis>every</emphasis> database operation. So even if you see it a few more times in
+ the following (very trivial) examples, consider <emphasis>session-per-operation</emphasis>
+ an anti-pattern. A real (web) application is shown later in this tutorial.
+ </para>
<para>
トランザクションの扱いと境界の詳しい情報については、
<xref linkend="transactions"/> を見てください。
@@ -1379,7 +1390,12 @@
データの読み書きに関わらず、すべてのデータアクセスはトランザクション内で行います。
(アプリケーション内ではオートコミットモードを使用しません)。
</para>
-
+ <para>
+ Do <emphasis>not</emphasis> use a new Hibernate <literal>Session</literal> for
+ every database operation. Use one Hibernate <literal>Session</literal> that is
+ scoped to the whole request. Use <literal>getCurrentSession()</literal>, so that
+ it is automatically bound to the current Java thread.
+ </para>
<para>
次に、リクエストのアクションは処理され、レスポンスであるHTMLが描画されます。
これについてはすぐに説明します。
More information about the hibernate-commits
mailing list