SpringBoot+Jpa+PostgreSQL配置多数据源

  • 使用的持久化框架为JPA,所以数据源也是基于JPA。采用的是SpringBoot2 + SpringDataJPA + postgresql + 双数据源!
  • 一:多数据源的使用场景
  • 二:application.yml中配置
  • 三、读取application.yml配置的两个数据源,并将其注入到Spring的IOC容器中
  • 四、以类的方式配置两个数据源
  • 五:注意点


使用的持久化框架为JPA,所以数据源也是基于JPA。采用的是SpringBoot2 + SpringDataJPA + postgresql + 双数据源!

一:多数据源的使用场景

1、主从库分离(数据库读写分离)

2、数据迁移

3、系统版本升级,数据库升级到另外一款

二:application.yml中配置

**spring:
  jpa:
    hibernate:
      ddl-auto: create
      naming:
        physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
        implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
    open-in-view: true
    show-sql: true
    generate-ddl: true

#多数据源配置
  datasource: #database
    primary:  # 业务信息数据库
      url: jdbc:postgresql://192.168.4.240:5432/cmcci
      username: postgres
      password: postgres
      driver-class-name: org.postgresql.Driver


    secondary:  # 空间地图数据库
      url: jdbc:postgresql://211.149.141.72:5432/xcu
      username: postgres
      password: lqkj!@#456
      driver-class-name: org.postgresql.Driver**

注:配置文件中需要指定两个数据源,如果需要多个数据源,像上面一样的配置,这里在配置的时候是没有自动提示的,因为这是我们自定义的,需要在程序中动态读取

三、读取application.yml配置的两个数据源,并将其注入到Spring的IOC容器中

@Configuration
    public class DataSourceConfig {
        @Bean(name = "primaryDataSource")
        @Qualifier("primaryDataSource")
        @Primary
        @ConfigurationProperties(prefix = "spring.datasource.primary")
        public DataSource primaryDataSource() {
            return DataSourceBuilder.create().build();
        }
    
        @Bean(name = "secondaryDataSource")
        @Qualifier("secondaryDataSource")
        @ConfigurationProperties(prefix = "spring.datasource.secondary")
        public DataSource secondaryDataSource() {
            return DataSourceBuilder.create().build();
        }
    
    }

注解解释:

@Configuration:SpringBoot启动将该类作为配置类,同配置文件一起加载

@Bean:将该实体注入到IOC容器中

@Qualifier:指定数据源名称,与Bean中的name属性原理相同,主要是为了确保注入成功

@Primary:指定主数据源

@ConfigurationProperties:将配置文件中的数据源读取进到方法中,进行build

四、以类的方式配置两个数据源

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "entityManagerFactoryPrimary",
        transactionManagerRef = "transactionManagerPrimary",
        basePackages = {"com.you07.booksearch.service.primary"})// 指定该数据源操作的DAO接口包
public class PrimaryConfig {
    @Autowired
    @Qualifier("primaryDataSource")
    private DataSource primaryDataSource;

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

    @Primary
    @Bean(name = "entityManagerFactoryPrimary")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary(EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(primaryDataSource)
                .properties(getVendorProperties())
                .packages("com.you07.booksearch.entity.primary")         //设置实体类所在位置
                .persistenceUnit("primaryPersistenceUnit")
                .build();
    }

    private Map getVendorProperties() {
        HashMap<String, Object> properties = new HashMap<>();
        properties.put("hibernate.dialect",
                env.getProperty("hibernate.dialect"));
        properties.put("hibernate.ddl-auto",
                "create");
        properties.put("hibernate.physical_naming_strategy",
                "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");
        properties.put("hibernate.implicit_naming_strategy",
                "org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy");
        return properties;
    }

    @Autowired
    private Environment env;

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

}

(2)次数据源

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "entityManagerFactorySecondary",
        transactionManagerRef = "transactionManagerSecondary",
        basePackages = {"com.you07.booksearch.service.secondary"}) //设置DAO接口层所在包位置

public class SecondaryConfig {
    @Autowired
    @Qualifier("secondaryDataSource")
    private DataSource secondaryDataSource;

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

    @Bean(name = "entityManagerFactorySecondary")
    public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary(EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(secondaryDataSource)
                .properties(getVendorProperties())
                .packages("com.you07.booksearch.entity.secondary")        //设置实体类所在包的位置
                .persistenceUnit("primaryPersistenceUnit")
                .build();
    }

    private Map getVendorProperties() {
        HashMap<String, Object> properties = new HashMap<>();
        properties.put("hibernate.hbm2ddl.auto",
                env.getProperty("hibernate.hbm2ddl.auto"));
        properties.put("hibernate.ddl-auto",
                env.getProperty("update"));
        properties.put("hibernate.dialect",
                env.getProperty("hibernate.dialect"));
        properties.put("hibernate.physical_naming_strategy",
                "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");
        properties.put("hibernate.implicit_naming_strategy",
                "org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy");
        return properties;
    }

    @Autowired
    private Environment env;

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

}

这两个类主要配置每个数据源,包括事务管理器、以及实体管理器等配置。

注:必须要指定DAO接口所在的包以及实体类所在的包。每个数据源主要操作它指定的资源(DAO接口CURD、实体类

五:注意点

1、SpringBoot启动类必须关闭 --程序启动加载的仓库(@EnableJpaRepositories),因为在数据源配置类中已经开启了。如果没有去掉,程序会跑不起来

@SpringBootApplication
@EnableTransactionManagement
//@EnableJpaRepositories(basePackages = {""})
public class BookSearchXcuApplication extends SpringBootServletInitializer {
      @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(BookSearchXcuApplication.class);
    }

    public static void main(String[] args) {
        new SpringApplicationBuilder(BookSearchXcuApplication.class).web(true).run(args);
    }

}

2、如果需要对数据源连接的表进行DDL(正向生成表、程序启动动态更新表),需要在PrimaryConfig类中 / SecondaryConfig类中的getVendorProperties()方法中进行手动设置(上面我都已设置好了!)