Hibernate EntityManagerその6 TransactionManager、CacheSynchronization

なんか中途半端に同じネタが続いてますが・・・調べる必要があって調べているのでまぁ仕方ない。
またまた、設定を変えてみました。今度の設定はこう

<entity-manager>
   <name>test</name>
   <jta-data-source>j2ee.dataSource</jta-data-source>
   <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
      <property name="hibernate.jndi.class" value="org.seasar.extension.j2ee.JndiContextFactory"/>
      <property name="hibernate.transaction.factory_class" value=" org.hibernate.transaction.CMTTransactionFactory"/>
      <property name="hibernate.transaction.manager_lookup_class" value="test.hibernate.S2TransactionManagerLookup"/>
      <property name="hibernate.show_sql" value="true"/>
      <property name="hibernate.format_sql" value="true"/>
      <property name="hibernate.use_sql_comments" value="true"/>
   </properties>
</entity-manager>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.3//EN" 
	"http://www.seasar.org/dtd/components23.dtd">
<components namespace="hibernate">

	<component class="org.hibernate.ejb.CurrentEntityManagerImpl" instance="prototype">
		<arg>emFactory.sessionFactory</arg>
	</component>
	
	<component name="emFactory" class="org.hibernate.ejb.HibernateEntityManagerFactory">
		<aspect>
			<component class="org.seasar.framework.aop.interceptors.DelegateInterceptor">
				<initMethod name="setTarget">
					<arg>@javax.persistence.Persistence@createEntityManagerFactory("test")</arg>
				</initMethod>
			</component>
		</aspect>
	</component>
	
</components>

TransactionFactoryの設定によって、EntityManagerのgetTransaction().begin()メソッドによって内部に作成されるorg.hibernate.Transactionの実装が変わるみたいですね。JDBCTransactionFactoryを指定するとConnectionによるトランザクション、JTATransactionFactoryだとUserTransactionによるトランザクション管理、CMTTransactionFactoryではTransactionManagerによるトランザクション管理になるみたいです。JTA環境の場合、EntityManager.getTransaction()を使用しない限り関係無さそうなんですが、一応自分が使うトランザクション環境に合わせて設定しておいた方が良さそうですね。今回はTransactionManagerまたはUserTransactionが使える環境なので、とりあえずCMTTransactionFactoryで設定してみました。また、EntityTransactionクラスがTransactionの開始・終了などの情報を持つので、EntityManagerのコンポーネントはprototypeで登録することにしました。でも、呼び出す側がsingletonなら意味無いんですが・・・ちょっと微妙かな?
また、AbstractEntityManagerImplの内部で、persist、merge、remove、refreshのメソッドを呼ぶときに、内部で呼び出したSessionを使って

( (SessionImplementor) getSession() ).isTransactionInProgress()

という処理を行っていました。最初に触ってた頃は、この部分は単にTransactionの存在チェックをしてるんだろうと思ってたのですが、メソッドをよく読むと、内部で

tx.registerSynchronization( new CacheSynchronization(owner, this, tx, null) );

こういう処理を行う場合があるみたいですね。基本的に、TransactionManagerLookupの設定が有効で、Sessionの「AutoCloseSession」または「FlushBeforeCompletion」または「ConnectionReleaseMode.AFTER_TRANSACTION」が有効になっていればSessionの新規作成時に関連付けられるみたいですが、設定によってはメソッド呼び出し時に初めて設定されることもあるみたいです。で、そこでregisterSynchronizationされるのがCacheSynchronizationというクラス。このクラスは、Transactionの各メソッドに対応して、Session内の指定されたメソッドを呼び出しているみたい。クラス名から察するに、Cache関連のトランザクションでしょうか? うーむ、HibernateってJTAと連携していろいろやってるんですね・・・基本的に、TransactionManagerLookupの設定は必ずやっておいた方がいいんだろうか? このCacheSynchronizationについては、もうちょっと調べて、何をやっているのか理解しておいた方が良さそう。