基于Spring Data JPA支持多数据源

一、在配置文件添加多数据源的配置

说明:

  • 单一数据源时,没有primarysecondary这一层级的配置
  • primarysecondary只是一个名称,可以根据实际情况进行命名,比如在使用druid数据源时可以把secondary改为druid,也是可以的
spring:
  datasource:
    # 主数据源
    primary:
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbc-url: jdbc:mysql://127.0.0.1:3306/data_studio?charset=utf8mb4&useSSL=false&serverTimezone=UTC
      username: ds
      password: 12345678
    # 辅助数据源
    secondary:
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbc-url: jdbc:mysql://127.0.0.1:3306/data_studio?charset=utf8mb4&useSSL=false&serverTimezone=UTC
      username: ds
      password: 12345678

  jpa:
    properties:
      hibernate:
        hbm2ddl:
          # 只验证表结构,不修改
          auto: validate
        dialect: org.hibernate.dialect.MySQL5InnoDBDialect
        jdbc:
          # 设置时区
          time_zone: Asia/Shanghai
        implicit_naming_strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
        physical_naming_strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
    # 无须打印SQL
    show-sql: false
    open-in-view: false

二、初始化数据源与JPA配置

只使用一个数据源时,Spring Data JPA能够自动识别JPA配置,并且初始化数据源。但在多数据源的场景下,必须手工初始化数据源。

2.1 创建多数据源的配置类

package cn.wesure.da.ds.manager.config;

import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

/**
 * @author chriscchen
 * @createtime 2021-02-05
 */
@Configuration
public class DataSourceConfig {

  // 不少教程是把jpaProperties、hibernateProperties、getVendorProperties放到具体的JPA配置中,代码重复冗余。
  // 可以把这两个属性、一个方法在这里自动注入来初始化,然后在对应的JPA配置中自动注入即可
  @Autowired
  private JpaProperties jpaProperties;

  @Autowired
  private HibernateProperties hibernateProperties;

  // 自动注入时的对象名称
  @Bean(name = "vendorProperties")
  public Map getVendorProperties() {
    return hibernateProperties
        .determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
  }

  // 主数据源,加上 @Primary。
  @Primary
  // 自动注入时的对象名称
  @Bean(name = "primaryDataSource")
  // 主数据源的配置项前缀
  @ConfigurationProperties("spring.datasource.primary")
  public DataSource primaryDataSource() {
    return DataSourceBuilder.create().build();
  }

  // 自动注入时的对象名称
  @Bean(name = "secondaryDataSource")
  // 辅助数据源的配置项前缀
  @ConfigurationProperties("spring.datasource.secondary")
  public DataSource secondaryDataSource() {
    return DataSourceBuilder.create().build();
  }
}

2.2 初始化不同数据源的JPA配置

JPA配置主要是告诉Spring Data JPA哪些Respository查询接口、domain模型类是属于哪个数据源

  • 在类名上通过注释 @EnableJpaRepositories 中指定Repository所在的位置

  • 在创建LocalContainerEntityManagerFactoryBean时,指domain模型类所在的位置

  • Primary数据源

package cn.wesure.da.ds.manager.config;

import java.util.Map;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * @author chriscchen
 * @createtime 2021-02-05
 */
@SuppressWarnings("ConstantConditions")
@Configuration
@EnableTransactionManagement
// 指定Primary数据源Repository的包名
@EnableJpaRepositories(
    entityManagerFactoryRef = "entityManagerFactoryPrimary",
    transactionManagerRef = "transactionManagerPrimary",
    basePackages = {"cn.wesure.da.ds.manager.repository.primary"})
public class PrimaryConfig {

  @Autowired
  @Qualifier("primaryDataSource")
  private DataSource primaryDataSource;

  // 自动注入在配置类中提供的初始化方法
  @Autowired
  @Qualifier("vendorProperties")
  private Map vendorProperties;

  @Primary
  @Bean(name = "entityManagerFactoryPrimary")
  public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary(
      EntityManagerFactoryBuilder builder) {
    // 指定模型类的包名
    return builder
        .dataSource(primaryDataSource)
        .properties(vendorProperties)
        .packages("cn.wesure.da.ds.manager.domain.primary")
        .persistenceUnit("primaryPersistenceUnit")
        .build();
  }

  @Primary
  @Bean(name = "entityManagerPrimary")
  public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
    return entityManagerFactoryPrimary(builder).getObject().createEntityManager();
  }

  @Primary
  @Bean(name = "transactionManagerPrimary")
  PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) {
    return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());
  }
}

  • Secondary数据源
package cn.wesure.da.ds.manager.config;

import java.util.Map;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * @author chriscchen
 * @createtime 2021-02-05
 */
@SuppressWarnings("ConstantConditions")
@Configuration
@EnableTransactionManagement
// 指定Secondary数据源Repository的包名
@EnableJpaRepositories(
    entityManagerFactoryRef="entityManagerFactorySecondary",
    transactionManagerRef="transactionManagerSecondary",
    basePackages= {"cn.wesure.da.ds.manager.repository.secondary"})
public class SecondaryConfig {

  @Autowired
  @Qualifier("secondaryDataSource")
  private DataSource secondaryDataSource;

  // 自动注入在配置类中提供的初始化方法
  @Autowired
  @Qualifier("vendorProperties")
  private Map vendorProperties;

  @Bean(name = "entityManagerFactorySecondary")
  public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary (
      EntityManagerFactoryBuilder builder) {
    // 指定模型类的包名
    return builder
        .dataSource(secondaryDataSource)
        .properties(vendorProperties)
        .packages("cn.wesure.da.ds.manager.domain.secondary")
        .persistenceUnit("secondaryPersistenceUnit")
        .build();
  }

  @Bean(name = "entityManagerSecondary")
  public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
    return entityManagerFactorySecondary(builder).getObject().createEntityManager();
  }

  @Bean(name = "transactionManagerSecondary")
  PlatformTransactionManager transactionManagerSecondary(EntityManagerFactoryBuilder builder) {
    return new JpaTransactionManager(entityManagerFactorySecondary(builder).getObject());
  }
}

至此已经完成Spring Data JPA的多数据源配置,后续只须按照不同的包创建Repositorydomain即可

你可能感兴趣的:(java,web开发,spring,boot,spring)