【问题标题】:JPA with Spring Data带有 Spring 数据的 JPA
【发布时间】:2014-06-25 09:44:39
【问题描述】:

我是 Java 新手,我需要创建一个控制台应用程序来连接 4 个数据库(access、vfp、mysql 和 sqlserver)。

我从 hibernate.cfg.xml 文件开始并设法配置它们,每个数据库一个。然后我意识到 jpa 是一个更好的解决方案。所以我把我所有的休眠文件都改成了一个有 4 个持久化单元的 persistence.xml 文件。

数据库运行良好,但要使用它们,我必须创建大量代码。这是一个例子:

EntityManagerFactory dbPersistence = 
   Persistence.createEntityManagerFactory("oneOfMyDatabases");

EntityManager em = dbPersistence.createEntityManager();

Query query = em.createQuery("from ProductEntity").setMaxResults(10);

for (Object o : query.getResultList()) {
    ProductEntity c = (ProductEntity) o;
    System.out.println("Product " + c.getName());
}

cgPersistence.close();

我需要使用其他数据库中的数据更新其中一个数据库。

像这样创建所有代码很痛苦,所以我在考虑创建存储库,但我不知道如何为每个数据库使用不同的 entityManagers 创建它们。

我尝试向管理器注入 google guice 没有成功,但我无法处理如何关闭或在哪里关闭持久连接。

最后,我找到了 Spring Data,它似乎是我需要的,但我并不真正了解如何使用它。

我需要一些指南来让它工作,因为我已经阅读了大量的教程,而且每个教程看起来都不一样: · 我可以使用相同的persistence.xml 还是需要另一个配置文件?我已经看到 Spring Data 具有 jpa 兼容性,但我不确定它是如何工作的。 · Spring Context是Spring Framework的IOC容器吗?我需要它来使用 Spring Data 吗? · 我还需要什么?

提前谢谢你

【问题讨论】:

  • 如果您在所有数据库中具有相同的架构,我建议您检查Spring's Dynamic DataSource Routing。如果没有,您需要创建 4 个数据源和 4 个实体管理器,正如 @vlad-mihalcea 指出的那样

标签: java spring hibernate jpa spring-data-jpa


【解决方案1】:

每个数据库都将由不同的数据源表示。对于每个数据源,您需要不同的会话工厂/实体管理器工厂。

如果您想在单个事务中保存多个数据源,则需要 XA 事务,因此需要 Java EE 或独立的事务管理器,如 Bitronix 或 Atomikos。

您有 4 个不同的实体管理器工厂,您还需要为每个工厂提供特定的存储库:

<jpa:repositories base-package="your.company.project.repository.access" entity-manager-factory-ref="accessEntityManagerFactory"/>

<jpa:repositories base-package="your.company.project.repository.sqlserver" entity-manager-factory-ref="sqlserverEntityManagerFactory"/>

那么您的应用程序不必关心它使用哪个存储库。

JpaTransactionManager 需要一个 entityManagerFactory,但由于您有 4 个,因此您最终可能会为此创建一个,我认为这是不可取的。

最好改用JTA:

<!-- 1. You define the Bitronix config ->
<bean id="btmConfig" factory-method="getConfiguration" class="bitronix.tm.TransactionManagerServices">
    <property name="serverId" value="spring-btm"/>
    <property name="warnAboutZeroResourceTransaction" value="true"/>
    <property name="logPart1Filename" value="${btm.config.logpart1filename}"/>
    <property name="logPart2Filename" value="${btm.config.logpart2filename}"/>
    <property name="journal" value="${btm.config.journal:disk}"/>
</bean>

<!-- 2. You define all your data sources ->
<bean id="dataSource" class="bitronix.tm.resource.jdbc.PoolingDataSource" init-method="init"
      destroy-method="close">
    <property name="className" value="${jdbc.driverClassName}"/>
    <property name="uniqueName" value="dataSource"/>
    <property name="minPoolSize" value="0"/>
    <property name="maxPoolSize" value="5"/>
    <property name="allowLocalTransactions" value="false"/>
    <property name="driverProperties">
        <props>
            <prop key="user">${jdbc.username}</prop>
            <prop key="password">${jdbc.password}</prop>
            <prop key="url">${jdbc.url}</prop>
        </props>
    </property>
</bean>

<!-- 3. For each data source you create a new  persistenceUnitManager and you give its own specific persistence.xml ->
<bean id="persistenceUnitManager" depends-on="transactionManager"
      class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
    <property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml"/>
    <property name="defaultDataSource" ref="dataSource"/>
    <property name="dataSourceLookup">
        <bean class="org.springframework.jdbc.datasource.lookup.BeanFactoryDataSourceLookup"/>
    </property>
</bean>

<!-- JpaDialect must be configured for transactionManager to make JPA and JDBC share transactions -->
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>

<!-- 4. For each data source you create a new entityManagerFactory ->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="persistenceUnit"/>
    <property name="persistenceUnitManager" ref="persistenceUnitManager"/>
    <property name="jpaDialect" ref="jpaDialect"/>
</bean>

<!-- 5. You have only one JTA transaction manager ->
<bean id="jtaTransactionManager" factory-method="getTransactionManager"
      class="bitronix.tm.TransactionManagerServices" depends-on="btmConfig, dataSource"
      destroy-method="shutdown"/>

<!-- 6. You have only one Spring transaction manager abstraction layer ->
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionManager" ref="jtaTransactionManager"/>
    <property name="userTransaction" ref="jtaTransactionManager"/>
</bean>

如果这证明您当前的问题工作量太大,您可以尝试拥有 4 个 JPA 事务管理器,看看它是如何工作的。

【讨论】:

  • 我认为除了这个错误“没有定义名为 'transactionManager' 的 bean”外,我一切正常。我可以对所有内容使用相同的事务管理器,还是必须为每个数据源定义一个不同的 TM?那就是说我不需要处理交易了?
  • 我不得不删除带有用户、密码和 url 的 ,因为我在每个属性中都收到了这条消息:没有可写属性 url|user|password。删除 driverProperties 后出现此错误:java.lang.ClassCastException: jstels.jdbc.dbf.DBFDriver2 无法转换为 javax.sql.XADataSource。可能驱动不兼容?
  • 大多数 DB 驱动程序都支持 XA,对于那个特定的驱动程序,您可以滚动 LRC Bitronix XA 包装器,允许您在全局 Tx 中最多登记一个非 XA 数据源。
  • 如果这对您当前的问题来说工作量太大,您可以尝试拥有 4 个 JPA 事务管理器,看看它是如何工作的。
  • 使用 JTA,您需要 1 个 Spring TM 和 1 个 Bitronix TM 而不是 4 个。您需要 4 个 DS 和 4 个 EMFactories。 Spring TM 只关心事务边界,而 Bitronix 是 XA TM 实现。
【解决方案2】:

如果您的架构在所有数据库中都相同,那么最好的方法是使用 hibernate,因为 hibernate 提供了多个数据库之间的可移植性。创建 hbm 文件和 pojo 类后,您唯一需要更改的就是方言和数据源。

事务管理器支持可以由spring提供。

【讨论】:

    猜你喜欢
    • 2020-07-31
    • 2021-05-26
    • 2017-02-20
    • 2014-09-02
    • 2018-01-08
    • 2015-06-20
    • 1970-01-01
    • 2021-09-06
    • 2018-11-05
    相关资源
    最近更新 更多