以下のテストは、Hibernate3 を使用した私のアプリケーションで機能していました。hibernate4にアップグレードすると、失敗し始めました。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(inheritLocations=false,locations={
"/hibernate/spring-SF-tests.xml",
"/hibernate/spring-transaction.xml",
"/hibernate/testBeans.xml"
,"/hibernate/spring-audit.xml",
"/hibernate/iwrs-mail-beans-test.xml",
"/hibernate/fake-audit-meaning.xml"
})
@TransactionConfiguration(transactionManager="txManager", defaultRollback=true)
public class CodeAuditIntegrationTest extends CodeIntegrationTest {
@Autowired
private SessionFactory auditFactory;
@Before
public void cleanAudit(){
auditFactory.getCurrentSession().createQuery("delete from AuditLogRecord").executeUpdate();
}
@Test
public void clinicalTrialAssociationTest() {
super.clinicalTrialAssociationTest();
}
}
失敗しているのは次のとおりです。
org.hibernate.HibernateException: org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:881) の org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97) で現在のスレッドのセッションが見つかりません
アプリには、sessionFactory と auditFactory という 2 つの異なるセッション ファクトリがあります。どちらも春に設定されます ([1] を参照)。
問題は、hibernate4 の構成で、プロパティの ExposureTransactionAwareSessionFactory が削除されたことです。auditFactory で true に設定しました。このプロパティを削除すると、注入された auditFactory がトランザクションでセッションを取得できなくなり (txManger が sessionFactory 用に構成されているため)、エラーが発生すると思います。
質問:
- このテストで、春に管理されたトランザクションを auditFactory に持たせるにはどうすればよいですか?
- それは、hibernate 3 の ExposureTransactionAwareSessionFactory プロパティで何が起こっていたのでしょうか?
私が見る唯一の代替手段は、auditFactory を使用するすべてのコードを、@Transactional(otherTxManager) の注釈が付けられたヘルパー クラスにラップすることです。私はそれを試しましたが、いくつかの追加の問題がありました。
- 別の DataSource を使用する必要がありました (それ以外の場合は [2] になります)
- 2 つの別々のデータソースを使用すると、Cucumber テストで同様のエラーが発生し、現在は transactionManager に関連しています [3]
[1] 関連する XML 構成:
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />
<bean id="sessionFactory" scope="singleton"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2dll}</prop>
<prop key="hibernate.hbm2ddl.import_files">${hibernate.sql_scripts}</prop>
</props>
</property>
<property name="packagesToScan">...</property>
<property name="annotatedPackages">...</property>
<property name="mappingLocations">...</property>
<property name="dataSource" ref="c3p0DataSource" />
<property name="entityInterceptor" ref="auditInterceptor" />
</bean>
<bean id="auditFactory" scope="singleton"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="exposeTransactionAwareSessionFactory"> -->needs to be removed in hibernate4!
<value>true</value>
</property>
<property name="mappingLocations">...</property>
<property name="packagesToScan">...</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2dll}</prop>
</props>
</property>
<property name="dataSource" ref="c3p0DataSource" />
</bean>
[2] 2 つのファクトリに同じ dataSource を使用する際の問題:
org.springframework.transaction.IllegalTransactionStateException: 事前にバインドされた JDBC 接続が見つかりました! HibernateTransactionManager は、DataSource 自体を管理するように指示された場合、DataSourceTransactionManager 内での実行をサポートしません。Hibernate アクセスか JDBC アクセスかに関係なく、単一の DataSource 上のすべてのトランザクションに対して単一の HibernateTransactionManager を使用することをお勧めします。org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:329) で
[3] 2 つのトランザクション マネージャーを宣言することによる cucumber テストの問題:
org.springframework.beans.factory.NoSuchBeanDefinitionException: タイプ [org.springframework.transaction.PlatformTransactionManager] の一意の Bean が定義されていません: 単一の Bean が予想されますが、2 が見つかりました: txAudit、txManager