web-dev-qa-db-ja.com

JPA(Hibernate)とJDBC(JdbcTemplateまたはMyBatis)が同じトランザクションを共有するようにSpringを構成する方法

DataSourceが1つあり、Spring 3.0.3、Hibernate 3.5.1をJPAプロバイダーとして使用し、一部のクエリにMyBatis 3.0.2を使用しており、アプリはTomcat 6で実行されています。両方を呼び出すと、HibernateDAOとMyBatisDAOがあります。 @Transactionalで注釈が付けられた同じメソッドからは、同じトランザクションを共有していないように見え、異なる接続を取得します。
どのようにして彼らにそうさせることができますか?

私はDataSourceUtils.getConnection(dataSource)から接続を取得しようとしましたが、MyBatisによって使用されている接続を取得しました。これは奇妙です。MyBatis構成に問題があり、JpaTransactionManagerを使用できないと思いました。 DataSoruceUtils.getConnectionを複数回呼び出しても、常に同じ接続が提供されます。これは問題ありません。

いくつかグーグルした後、私はspring-instrument-Tomcatのクラスローダーを試しました(Tomcatが本当にそれを使用しているかどうかはわかりませんが:))

部分的なapplicationContext

<bean class="org.Apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
    <property name="driverClassName" value="${database.driverClassName}"/>
    <property name="url" value="${database.url}"/>
    <property name="username" value="${database.username}"/>
    <property name="password" value="${database.password}"/>
</bean>

<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>

<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
    <property name="dataSource" ref="dataSource"/>
</bean>

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="configLocation" value="classpath:META-INF/mybatis/mybatis-config.xml" />
</bean>

mybatis設定の一部

<settings>
    <setting name="cacheEnabled" value="false" />
    <setting name="useGeneratedKeys" value="false" />
    <setting name="defaultExecutorType" value="REUSE" />
    <setting name="lazyLoadingEnabled" value="false"/>
</settings>

一部のpersistence.xml

<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
25
tewe

私はここで解決策を見つけました: JPAを使用する場合、JBDCテンプレートにどのトランザクションマネージャーを使用する必要がありますか?

DataSourceTransactionManagerではなく、JpaTransactionManagerを使用しています。
JavaDoc http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/orm/jpa/JpaTransactionManager.html

このトランザクションマネージャは、トランザクション内での直接DataSourceアクセスもサポートします(つまり、同じDataSourceで動作するプレーンなJDBCコード)。これにより、JPAにアクセスするサービスとプレーンなJDBCを使用するサービスを(JPAを意識せずに)混在させることができます。アプリケーションコードは、DataSourceTransactionManagerと同じ単純な接続ルックアップパターン(つまり、DataSourceUtils.getConnection(javax.sql.DataSource)またはTransactionAwareDataSourceProxyを通過する)に従う必要があります。 これには、ベンダー固有のJpaDialectを構成する必要があることに注意してください。

EntityManagerFactory構成にjpaVendorAdapterを追加すると、すべてが機能し、JdbcTemplateクエリとMyBatisの両方が同じトランザクションで期待どおりに実行されます。 JavaDocに基づいて、jpaDialectで十分だと思いますが、ここでは午前4時なので、今は試しません:)

<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
    <property name="persistenceUnitName" value="persistenceUnit"/>
    <property name="dataSource" ref="dataSource"/>
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="showSql" value="true" />
            <property name="generateDdl" value="true" />
            <property name="databasePlatform" value="org.hibernate.dialect.PostgreSQLDialect" />
        </bean>
    </property>
</bean>
35
tewe

私にはMyBatisがありませんが、teweが提案したように、jpaDialectをtransactionManagerに追加するだけで十分です。

<bean class="org.springframework.orm.jpa.JpaTransactionManager"
    id="transactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
    <property name="jpaDialect">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
    </property>
</bean>
4
sbk