【问题标题】:Configuring multiple databases with multiple entitymanagerfactory in spring data jpa在spring data jpa中使用多个entitymanagerfactory配置多个数据库
【发布时间】:2018-04-11 05:18:58
【问题描述】:

我想在春季 4 为 2 个不同的数据库(postgres 和 sql server)配置 2 个实体管理器工厂。

persistence.xml 包含 2 个用于 2 个数据库的持久性单元:

 <?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
    <persistence-unit name="entityManager">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL9Dialect"/>
            <property name="hibernate.show_sql" value="false"/>
            <property name="hibernate.hbm2ddl.auto" value="validate"/>
            <property name="hibernate.temp.use_jdbc_metadata_defaults" value="false"/>
        </properties>
    </persistence-unit>

    <persistence-unit name="sqlEntityManager">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect"/>
            <property name="hibernate.show_sql" value="false"/>
            <property name="hibernate.hbm2ddl.auto" value="validate"/>
            <property name="hibernate.temp.use_jdbc_metadata_defaults" value="false"/>
        </properties>
    </persistence-unit>
</persistence>

spring-context.xml 包含 2 个数据源和 2 个实体管理器工厂:

    <bean id="postgresDataSource"
          class="org.springframework.jdbc.datasource.DriverManagerDataSource"
          p:driverClassName="org.postgresql.Driver"
          p:url="jdbc:postgresql://localhost:5432/test?createDatabaseIfNotExist=true"
          p:username="test"
          p:password="test"/>

    <bean id="sqlDataSource"
          class="org.springframework.jdbc.datasource.DriverManagerDataSource"
          p:driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
          p:url="jdbc:sqlserver://localhost:1433;databaseName=test"
          p:username="test"
          p:password="test"/>


    <bean id="persistenceUnit" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
        <property name="persistenceXmlLocations">
            <list>
                <value>classpath*:META-INF/persistence.xml</value>
            </list>
        </property>
        <property name="defaultDataSource" ref="postgresDataSource"/>
    </bean>

    <bean id="sqlPersistenceUnit" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
        <property name="persistenceXmlLocations">
            <list>
                <value>classpath*:META-INF/persistence.xml</value>
            </list>
        </property>
        <property name="defaultDataSource" ref="sqlDataSource"/>
    </bean>



    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitManager" ref="persistenceUnit"/>
        <property name="persistenceUnitName" value="entityManager"/>
<property name="packagesToScan" value="com.test.entities.postgres"/>
    </bean>

    <bean id="sqlEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitManager" ref="sqlPersistenceUnit"/>
        <property name="persistenceUnitName" value="sqlEntityManager"/>
<property name="packagesToScan" value="com.test.entities.sql"/>
    </bean>

当我运行应用程序时,它无法创建 entitymangerfactory,因为它正在检查 sql server 中的 postgres 中的表。

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in ServletContext resource [/WEB-INF/spring-context.xml]: Invocation of init method failed; nested exception is org.hibernate.HibernateException: Missing table:<SqlServerTableName>

【问题讨论】:

    标签: java spring spring-data-jpa


    【解决方案1】:

    我可以通过删除 persistence.xml 并在 context.xml 中创建 entitymanagerfactory 和 pcentitymanagerfactory 来解决问题,如下所示:

    <bean id="entityManagerFactory"
          class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
          p:dataSource-ref="phoenixDataSource">
        <property name="packagesToScan">
            <array>
                <value>com.test.entities.postgres</value>
            </array>
        </property>
    
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
        </property>
    
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL9Dialect</prop>
                <prop key="hibernate.show_sql">false</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>
    
        </bean>
    

    因为如果我们使用 persistence.xml,packagesToScan 不起作用。

    【讨论】:

    • 基于注解的配置使用 @Configuration @EnableJpaRepositories(entityManagerFactoryRef="factory1", basePackages={"my.repository.package"}) 注解让事情变得更简单。只要基本包和引用是唯一的,您就可以根据需要汇总任意数量的不同数据源。
    • 这是一个有很多配置的旧应用程序,所以我不想将所有基于 xml 的配置更改为基于注释的配置
    • 啊,好吧,那将是一个危险的重构
    【解决方案2】:

    请通过此更新您的休眠配置。我想这会对你有所帮助

    <property name="hibernate.hbm2ddl.auto">create</property>
    or 
    <property name="hibernate.hbm2ddl.auto">update</property>
    

    【讨论】:

    • 我改变了它们是在 postgres 中创建 sql server 表
    • 所以只需使用 sql 创建并使用 postgres 验证
    • 我不想在 postgres 或 sql server 中创建/更新任何表,因为它们是生产数据库
    • 然后确保数据库中的所有表都已可用,您将要使用这些表。
    • 所有表都已经可用 postgres 表映射到 com.test.entities.postgres 包中的实体,而 sqlserver 表映射到 com.test.entities.sql 包中的实体,这就是我使用的原因entitymanagerfactory 配置中的 packagesToScan 属性
    【解决方案3】:

    我有一个包含两个实体管理器的应用程序。这是我的配置:

    persistence.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="2.1"
        xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    
        <persistence-unit name="myapp" transaction-type="RESOURCE_LOCAL">
            <class>...</class>
            <class>...</class>
        </persistence-unit>
    
        <persistence-unit name="proxies" transaction-type="RESOURCE_LOCAL">
            <class>...</class>
            <class>...</class>
        </persistence-unit>
    
    </persistence>
    

    spring-context.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
        xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:task="http://www.springframework.org/schema/task"
        xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
            http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    
        <tx:annotation-driven transaction-manager="transactionManager" />
        <tx:annotation-driven transaction-manager="transactionManagerProxy" />
    
        <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
            <property name="dataSource" ref="myappDataSource" />
            <property name="entityManagerFactory" ref="entityManagerFactory" />
        </bean>
    
        <bean id="transactionManagerProxy" class="org.springframework.orm.jpa.JpaTransactionManager">
            <property name="dataSource" ref="proxyDataSource" />
            <property name="entityManagerFactory" ref="entityManagerFactoryProxy" />
        </bean>
    
        <jpa:repositories base-package="com.example.myapp.repository" entity-manager-factory-ref="entityManagerFactory" />
        <jpa:repositories base-package="com.example.myapp.repository.proxy" entity-manager-factory-ref="entityManagerFactoryProxy" />
    
        <task:annotation-driven />
    
        <!-- holding properties for database connectivity /-->
       <context:property-placeholder location="classpath:database.properties"/>
    
        <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
            <property name="packagesToScan" value="com.example.myapp.model" />
            <property name="persistenceUnitName" value="myapp" />
            <property name="dataSource" ref="myappDataSource" />
            <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
        </bean>
    
        <bean id="entityManagerFactoryProxy" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
            <property name="packagesToScan" value="com.example.myapp.model.proxy" />
            <property name="persistenceUnitName" value="proxy" />
            <property name="dataSource" ref="proxyDataSource" />
            <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
        </bean>
    
        <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="database" value="MYSQL"/>
            <property name="showSql" value="false"/>
            <property name="generateDdl" value="false"/>
            <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/>
        </bean>
    
        <bean id="dataSource" abstract="true" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
            <property name="driverClass" value="${jdbc.driverClassName}" />
            <property name="maxPoolSize" value="${jdbc.maxPoolSize}" />
            <property name="minPoolSize" value="${jdbc.minPoolSize}" />
            <property name="maxStatements" value="${jdbc.maxStatements}" />
            <property name="testConnectionOnCheckout" value="${jdbc.testConnectionOnCheckout}" />
            <property name="checkoutTimeout" value="${jdbc.checkoutTimeout}"/>
            <property name="acquireIncrement" value="${jdbc.acquireIncrement}"/>
            <property name="idleConnectionTestPeriod" value="${jdbc.idleConnectionTestPeriod}"/>
            <property name="preferredTestQuery" value="${jdbc.preferredTestQuery}"/>
        </bean>
    
        <bean id="myappDataSource" parent="dataSource">
            <property name="jdbcUrl" value="${jdbc.url}" />
            <property name="user" value="${jdbc.username}" />
            <property name="password" value="${jdbc.password}" />
        </bean>
    
        <bean id="proxyDataSource" parent="dataSource">
            <property name="jdbcUrl" value="${jdbc.proxy.url}" />
            <property name="user" value="${jdbc.proxy.username}" />
            <property name="password" value="${jdbc.proxy.password}" />
        </bean>
    
    </beans>
    

    我有 2 个到 MySql 的连接,但对于两个不同的数据库应该是相同的。

    【讨论】:

    • 在 peristence.xml 中,我们必须将添加到应用程序中的每个新实体作为 或 jar 输入,这很乏味。所以我避免了这种情况,只是使用 packagesToScan 属性来为我完成这项工作。
    猜你喜欢
    • 2019-07-24
    • 2012-04-11
    • 2016-10-21
    • 1970-01-01
    • 2015-10-02
    • 1970-01-01
    • 2017-12-12
    • 2013-05-09
    • 1970-01-01
    相关资源
    最近更新 更多