如何配置Spring让JPA(Hibernate)和JDBC(JdbcTemplate或MyBatis)共享同一个事务 [英] How to configure Spring to make JPA (Hibernate) and JDBC (JdbcTemplate or MyBatis) share the same transaction

查看:96
本文介绍了如何配置Spring让JPA(Hibernate)和JDBC(JdbcTemplate或MyBatis)共享同一个事务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个数据源,我使用 Spring 3.0.3、Hibernate 3.5.1 作为 JPA 提供者,我使用 MyBatis 3.0.2 进行一些查询,我的应用程序在 Tomcat 6 上运行.我有一个 HibernateDAO 和一个 MyBatisDAO,当我从用@Transactional 注释的相同方法调用两者,看起来它们不共享相同的事务,它们获得不同的连接.
我怎样才能让他们去做?

I have a single dataSource, I use Spring 3.0.3, Hibernate 3.5.1 as JPA provider and I use MyBatis 3.0.2 for some queries and my app runs on Tomcat 6. I have a HibernateDAO and a MyBatisDAO, when I call both from the same method which is annotated with @Transactional it looks like they don't share the same transaction, they get different connections.
How can I make them to do?

我已经尝试从 DataSourceUtils.getConnection(dataSource) 获取连接,但我得到了 MyBatis 使用的连接,这很奇怪,我认为问题出在 MyBatis 配置中,它不能使用 JpaTransactionManager.即使多次调用 DataSoruceUtils.getConnection 也总是提供相同的连接,这没关系.

I've tried getting a connection from DataSourceUtils.getConnection(dataSource) and I get the one which is used by MyBatis which is strange I thought the problem was in MyBatis config and it can't use JpaTransactionManager. Even calling multiple times DataSoruceUtils.getConnection gives the same connection always, which is ok.

经过一番谷歌搜索后,我尝试了 spring-instrument-tomcat 的类加载器(虽然我不知道 tomcat 是否真的使用它:))

After some googling I've tried spring-instrument-tomcat's classloader (although I don't know if tomcat really uses it :))

部分应用上下文

<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 部分配置

partial mybatis config

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

部分持久性.xml

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

推荐答案

我在这里找到了解决方案:JBDC 模板应该使用什么事务管理器 使用 JPA 时?

I've found the solution here: What transaction manager should I use for JBDC template When using JPA ?

我使用的是 JpaTransactionManager 而不是 DataSourceTransactionManager.
JavaDoc http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/orm/jpa/JpaTransactionManager.html

I'm using JpaTransactionManager and not DataSourceTransactionManager.
JavaDoc http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/orm/jpa/JpaTransactionManager.html

此事务管理器还支持事务内的直接数据源访问(即使用相同数据源的普通 JDBC 代码).这允许混合访问 JPA 的服务和使用普通 JDBC 的服务(不知道 JPA)!应用程序代码需要坚持与 DataSourceTransactionManager 相同的简单连接查找模式(即 DataSourceUtils.getConnection(javax.sql.DataSource) 或通过 TransactionAwareDataSourceProxy).请注意,这需要配置特定于供应商的 JpaDialect.

This transaction manager also supports direct DataSource access within a transaction (i.e. plain JDBC code working with the same DataSource). This allows for mixing services which access JPA and services which use plain JDBC (without being aware of JPA)! Application code needs to stick to the same simple Connection lookup pattern as with DataSourceTransactionManager (i.e. DataSourceUtils.getConnection(javax.sql.DataSource) or going through a TransactionAwareDataSourceProxy). Note that this requires a vendor-specific JpaDialect to be configured.

在我将 jpaVendorAdapter 添加到我的 entityManagerFactory 配置后,一切正常,JdbcTemplate 查询和 MyBatis 都按预期在同一个事务中运行.基于 JavaDoc,我想 jpaDialect 应该足够了,但现在是凌晨 4 点,所以我现在不会尝试 :)

After I've added jpaVendorAdapter to my entityManagerFactory config everything works, both JdbcTemplate query and MyBatis runs in the same transaction as expected. Based on the JavaDoc I guess a jpaDialect should be enough but it's 4 a.m. here so I won't try that now :)

<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>

这篇关于如何配置Spring让JPA(Hibernate)和JDBC(JdbcTemplate或MyBatis)共享同一个事务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆