Spring 启动 JPA 设置自定义数据源

Spring boot JPA set custom datasource

我定义了 2 个数据源-

#datasource jndi setup
database.datasources[1].jndi-name=jdbc/yyyy
database.datasources[1].username=yyyy
database.datasources[1].password=yyyyy
database.datasources[1].url=jdbc:oracle:thin:@localhost:2222:webtst
database.datasources[1].driverClassName=oracle.jdbc.OracleDriver
database.datasources[1].factory=org.apache.tomcat.jdbc.pool.DataSourceFactory
database.datasources[1].initialSize=1
database.datasources[1].maxActive=5

database.datasources[0].jndi-name=jdbc/xxx
database.datasources[0].username=xxx
database.datasources[0].password=xxxx
database.datasources[0].url=jdbc:oracle:thin:@localhost:2222:webtst
database.datasources[0].driverClassName=oracle.jdbc.OracleDriver
database.datasources[0].factory=org.apache.tomcat.jdbc.pool.DataSourceFactory
database.datasources[0].initialSize=1
database.datasources[0].maxActive=15 

和 2 个匹配的 JPA 存储库,在我将其中一个定义为 @Primary 之后,如何设置其中一个使用不同的 ds(不是主要的 ds):

@Bean
@Primary
DataSource dataSource() throws SQLException {
    OracleDataSource dataSource = new OracleDataSource();
    dataSource.setUser(xusername);
    dataSource.setPassword(xpassword);
    dataSource.setURL(xurl);

    dataSource.setImplicitCachingEnabled(true);
    dataSource.setFastConnectionFailoverEnabled(true);
    return dataSource;
}



@Bean
DataSource propsDataSource() throws SQLException {
    OracleDataSource propsDataSource = new OracleDataSource();
    //propsDataSource.setDataSourceName(secJNDIName);
    propsDataSource.setUser(yUserName);
    propsDataSource.setPassword(ypropsPassword);
    propsDataSource.setURL(upropsUrl);
    propsDataSource.setImplicitCachingEnabled(true);
    propsDataSource.setFastConnectionFailoverEnabled(true);
    return propsDataSource;
}

还有一个简单的 JpaRepository,我希望它使用二级数据源:

public interface AttributesRepo extends JpaRepository<PRODUCTATTRIBUTE, PRODUCTATTRIBUTE_KEY> {

}

您需要:

  • 定义两个DataSource
  • 将其中之一标记为 @Primary(就像您所做的那样)
  • 定义两个 LocalContainerEntityManagerFactoryBean em1em2 每个使用不同的 DataSource
  • 定义两个TransactionManagers
  • 将所有应该使用第一个 DataSource 的存储库放入包 pkg1 中,将其他存储库放入包 pkg2
  • 定义一个 @Configuration class with @EnableJpaRepositories with basePackages = "pkg1" and entityManagerFactoryRef = "em1"
  • 第二个 @Configuration class 为 pkg2em2

Spring 引导文档中有描述 - 84.10 使用两个 EntityManagers .

我使用两个数据源。这是我的 applicationContext.xml:

<?xml version = "1.0" encoding = "UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:util="http://www.springframework.org/schema/util"
   xmlns:context="http://www.springframework.org/schema/context"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:tx="http://www.springframework.org/schema/tx"
   xmlns:jpa="http://www.springframework.org/schema/data/jpa"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans.xsd
   http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context.xsd
   http://www.springframework.org/schema/tx
   http://www.springframework.org/schema/tx/spring-tx.xsd
   http://www.springframework.org/schema/util
   http://www.springframework.org/schema/util/spring-util.xsd
   http://www.springframework.org/schema/data/jpa
   http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
   http://www.springframework.org/schema/data/jpa
   http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

<jpa:repositories base-package="nl.christine.schwartze.server"/>

<context:property-placeholder location="classpath:/META-INF/database.properties"/>

<context:component-scan base-package="nl.christine.schwartze.server"/>

<bean class="org.apache.commons.dbcp2.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.apache.commons.dbcp2.BasicDataSource"
      destroy-method="close" id="importDataSource">
    <property name="driverClassName" value="${database.driverClassName}"/>
    <property name="url" value="${importDatabase.url}"/>
    <property name="username" value="${database.username}"/>
    <property name="password" value="${database.password}"/>
</bean>

<bean id="entityManagerFactory"
      class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="defaultPU"/>
    <property name="dataSource" ref="dataSource"/>
    <property name="packagesToScan" value="nl.christine.schwartze.server.model"/>
    <property name="jpaVendorAdapter" ref="hibernateVendorAdapter"/>
    <property name="jpaProperties" ref="props"/>
    <property name="persistenceProvider">
        <bean class="org.hibernate.jpa.HibernatePersistenceProvider"/>
    </property>
</bean>

<bean id="importEntityManagerFactory"
      class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="importPU"/>
    <property name="dataSource" ref="importDataSource"/>
    <property name="packagesToScan" value="nl.christine.schwartze.server.modelimport"/>
    <property name="jpaVendorAdapter" ref="hibernateVendorAdapter"/>
    <property name="jpaProperties" ref="importprops"/>
    <property name="persistenceProvider">
        <bean class="org.hibernate.jpa.HibernatePersistenceProvider"/>
    </property>
</bean>

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

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

<bean id="hibernateVendorAdapter"
      class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>

<util:properties id="props">
    <prop key="hibernate.show_sql">true</prop>
    <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL82Dialect</prop>
    <prop key="hibernate.hbm2ddl.auto">${database.createorvalidate}</prop>
    <prop key="hibernate.ddl-auto">${database.createorvalidate}</prop>
    <prop key="spring.jpa.show-sql">true</prop>
    <prop key="spring.jpa.generate.ddl">true</prop>
    <prop key="spring.jpa.hibernate.ddl-auto">${database.createorvalidate}</prop>
    <prop key="spring.datasource.initialization-mode">never</prop>
    <prop key="spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation">true</prop>
</util:properties>

<util:properties id="importprops">
    <prop key="hibernate.show_sql">true</prop>
    <prop key="hibernate.id.new_generator_mappings">false</prop>
    <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL82Dialect</prop>
    <prop key="hibernate.hbm2ddl.auto">validate</prop>
    <prop key="hibernate.ddl-auto">validate</prop>
    <prop key="spring.jpa.show-sql">true</prop>
    <prop key="spring.jpa.generate.ddl">true</prop>
    <prop key="spring.jpa.hibernate.ddl-auto">validate</prop>
    <prop key="spring.datasource.initialization-mode">never</prop>
    <prop key="spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation">true</prop>
</util:properties>

<bean id="importLetterDao" class="nl.christine.schwartze.server.daoimport.impl.ImportLetterDaoImpl" scope="singleton">
</bean>

<bean id="letterDao" class="nl.christine.schwartze.server.dao.impl.LetterDaoImpl" scope="singleton">
</bean>

<bean id="locationDao" class="nl.christine.schwartze.server.dao.impl.LocationDaoImpl" scope="singleton">
</bean>

<bean id="personDao" class="nl.christine.schwartze.server.dao.impl.PersonDaoImpl" scope="singleton">
</bean>

<bean id="letterService" class="nl.christine.schwartze.server.service.impl.LetterServiceImpl" scope="singleton">
</bean>

<bean id="logger" scope="prototype" class="org.slf4j.LoggerFactory" factory-method="getLogger">
    <constructor-arg name="name" value="schwartzeLogger" />
</bean>

这是域之一的一部分 类:

@Entity
@Table(name = "letters")
@EnableJpaRepositories(
    basePackages = "nl.christine.schwartze.server.dao",
    transactionManagerRef = "transactionManager",
    entityManagerFactoryRef = "defaultPU")
public class Letter {
...

这些是我在控制器方法上的注释:

   @CrossOrigin(origins = "http://pengo.christine.nl:3000")
@RequestMapping(method = RequestMethod.POST, value = "/get_letters/")
@Transactional("transactionManager")
public ResponseEntity<LettersResult> getLetters(@RequestBody LettersRequest request) {
...

示例项目 here