ラベル Hibernate Session スコープ戦略 の投稿を表示しています。 すべての投稿を表示
ラベル Hibernate Session スコープ戦略 の投稿を表示しています。 すべての投稿を表示

2014年4月28日月曜日

Hibernate Session スコープ戦略 3/3 (FMP設定編)

 Flow Managed Persistence (FMP) の設定方法の説明です。
 この戦略は Spring Web Flow (SWF)を利用します。 FMP を使う場合は、 OSIV の設定は不要です。 設定方法は、 SWF の Listener を設定している xml ファイルに、以下を記述すれば良いです。 JPA の場合は、以下のように記述を追加します。
<webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry">
    <webflow:flow-execution-listeners>
        <webflow:listener ref="jpaFlowExecutionListener" />
    </webflow:flow-execution-listeners>
</webflow:flow-executor>
 
<bean id="jpaFlowExecutionListener" 
      class="org.springframework.webflow.persistence.JpaFlowExecutionListener">
    <constructor-arg ref="entityManagerFactory" />
    <constructor-arg ref="transactionManager" />
</bean>
JPA を使わず Hibernate のみの場合は、以下のように記述を追加します。
<webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry">
    <webflow:flow-execution-listeners>
        <webflow:listener ref="hibernateFlowExecutionListener" />
    </webflow:flow-execution-listeners>
</webflow:flow-executor>
 
<bean id="hibernateFlowExecutionListener" 
      class="org.springframework.webflow.persistence.HibernateFlowExecutionListener">
    <constructor-arg ref="sessionFactory" />
    <constructor-arg ref="transactionManager" />
</bean>
あとは、各々のスコープを利用するフローの xml に、
<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/webflow
                          http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">

    <persistence-context />
    
    ....
    
</flow>
のように、そのフローのスコープ内で Hibernate の Session が生きていることを設定します。 そして、スコープの終わりには、
<end-state id="bookingConfirmed" commit="true" />

のように記述することで、トランザクションのコミットと同時に Session を閉じるようにします。
 以上で、 FMP の設定は終わりです。

 まとめ
 SWF の FMP を使うことで、手動で Hibernate  と同期すること、つまり分離(detach)と付加(attach)を操作することなく、そのフロースコープを定義することで自動で同期してくれます。 References
Open Session in View by Hibernate Community https://community.jboss.org/wiki/OpenSessionInView
Spring Web Flow 2 でのフロー・マネージド・パーシスタンス by IBM
OSIV by Spring Forum
OSIVF vs OSIVI
Session Strategy by Hibernate Reference

Hibernate Session スコープ戦略 2/3 (OSIV設定編)

意外と見られていたので、放置しておいてた Hibernnate の記事を追記していきます。
別のサイトに書いて置いたものをここに持ってきただけですけどね。

OSIV と FMP の設定方法について説明していきます。 OSIV, FMP どちらも Spring の設定方法自体は簡単です。 Open Session In View (OSIV) の設定方法 まず Open Session In View (OSIV) ですが、 Spring には 2つの解決方法があります。
  1. OpenSessionInViewFilter
  2. OpenSessionInViewInterceptor
OpenSessionInViewInterceptor は Spring MVC を利用する場合に使えるクラスです。 よって、 Spring Web Flow を使うときは、 1. OpenSessionInViewFilter になります。 その設定方法ですが、 JPA を利用する場合は、以下のような設定を web.xml に記述するだけです。
<filter>
    <filter-name>oemivFilter</filter-name>
    <filter-class>
        org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
    </filter-class>
    <init-param>
        <param-name>entityManagerFactoryBeanName</param-name>
        <param-value>reportsEntityManagerFactory</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>oemivFilter</filter-name>
    <!-- ↓このパターンは利用する画面のURLに合わせてください -->
    <url-pattern>*.jsp</url-pattern>
</filter-mapping>
<>タグ記号の変換ってめんどくさい...。 JPA なしの Hibernate だけで利用する場合は、以下のような設定を web.xml に記述します。 Filter クラスが変わるだけですね。
<filter>
    <filter-name>oemivFilter</filter-name>
    <filter-class>
        org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
    </filter-class>
    <init-param>
        <param-name>entityManagerFactoryBeanName</param-name>
        <param-value>reportsEntityManagerFactory</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>oemivFilter</filter-name>
    <!-- ↓このパターンは利用する画面のURLに合わせてください -->
    <url-pattern>*.jsp</url-pattern>
</filter-mapping>
これらの説明はなぜか Reference には書いておらず JavaDoc にしか記述がありません。 FMP 戦略にするなら、この設定は不要です。 これで、 OSIV の設定は終わりで、自動にビューレンダリングまで Session を開いてくれます。

T.B.C.

2012年6月18日月曜日

Hibernate Session スコープ戦略 1/3 (理論編)

Hibernate を利用した場合のドメインオブジェクトの同期範囲の扱いについて、日本語リソースが少ないため、ここで解説しておきます。 ブログという都合上かなり簡略化して書いている部分もあります。 Hibernate の Session のスコープをどう扱うかという戦略(Session スコープ戦略 / Session 引き回し戦略 とでも言いましょうか)についてです。 Hibernate + Spring を基本に書いています。

Hibernate の Session は、 Spring と一緒に利用するとき、基本的にはトランザクションが終了すると Session も閉じることになり、エンティティ(ドメインオブジェクト)と SessionFactory の同期が外れます(*1)。 
*1 同期が外れていることを分離(detach)と言います。分離しているエンティティを分離オブジェクト(detached object)と言います。
Lazy Loading (レイジーローディング) を利用しているとき(これは Hibernate の default 設定)、トランザクション終了した(Session が閉じた)あとにエンティティのトランザクション開始時から実行していない getter を実行すると、以下のような LazyInitializationException が発生することになります。

org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:86)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:140)
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
...

 そして、このままであると不都合があります。
  1. 画面で随時取りたい項目が取れない(画面では LazyLoading が利用できない)
  2. 画面間で同じドメインオブジェクトを利用するにしても再度取得しないといけない(画面間楽観排他)
もし分散処理で業務処理と画面処理が SOAP などのプロトコルを介して分かれているなら、事前に getter を動かしておく、 Eager Fetch で取得しておくなどして、甘んじて受け入れることになりますが、同じ筐体であれば解決したいところです。 すなわち、ドメインオブジェクトの値を取得したいその間に Session を開いたままにしておくことができれば、この問題は解決できます。Hibernate の Session を開いたまま引き回すということです。 Hibernate の Session を引き回す戦略は、2つあります。
  1. Open Session In View (OSIV) オープン・セッション・イン・ビュー
  2. Flow Managed Persistence (FMP) フロー・マネジド・パーシスタンス
1. の OpenSessionInView (OSIV) とは、 一度のリクエストからレスポンスの範囲で Session を開いたままにするという設計戦略です。この戦略には、 Spring Framework で用意している OpenSessionInViewFilter を利用すると別途実装なしに設定できます。不都合の 1. に対応します。 2. の Flow Managed Persistence (FMP) とは、複数画面を跨いで自由に設定した範囲で Session を開いたままにするという設計戦略です。この戦略には、 Spring Web Flow (SWF) を利用すると別途実装なしに設定できます。 SWF のスコープを利用してその範囲で Session を開いたままにします。不都合の 2. に対応します。 まとめると以下のとおりです。
Hibernate Session のスコープ戦略パターン
戦略パターン スコープ 解決する問題 手段
オープン・セッション・イン・ビュー (OSIV) 1リクエスト (Session-per-request) ビューのレンダリングで LazyLoading に関するエラーが出る Spring で用意している SessionInViewFilter クラス
フロー・マネジド・パーシスタンス(FMP) 1カンバセーション(Session-per-conversation) 画面やボタンを跨ぐ一連の処理(長い UnitOfWork)で、Session に手動でドメインオブジェクトを同期しないといけない(e.g. session.reflesh() )。 Spring Web Flow
もし SWF を使わないのなら、 FMP は自分で手動実装することになるでしょう。 また EJBサーバーを用意して JBoss Seam を使う場合なら、FMP同様のことができるかと思います。 つまり SWF を使う場合は、 FMP を使うと良いということになります。 実際の設定方法は次回へ。
T.B.C.

Scala on VSCode

Scala on VSCode ===================== Docker を利用した VSCode remote development 上で Scala 開発をする方法 Links ========== ## Scala on VSCode remote...