springdata-jpa multiple data source configuration

Project structure

1. Dependence

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.18</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <!-- MySQL driver, note, this needs to correspond to the MySQL version -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.31</version>
        <scope>runtime</scope>
    </dependency>
    <!--web-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--fastjson-->
    <dependency>
        <groupId>com.alibaba.fastjson2</groupId>
        <artifactId>fastjson2</artifactId>
        <version>2.0.4</version>
    </dependency>
</dependencies>

2.application.yml

server:
  port: 8900 #Port
spring:
  datasource:
    #Main data source
    primary:
      url: jdbc:mysql://192.168.64.132:3306/testdb?serverTimezone=GMT & amp;seUnicode=true & amp;characterEncoding=UTF-8 & amp;useSSL=false & amp;allowMultiQueries=true & amp;autoReconnect= true &allowPublicKeyRetrieval=true
      username: root
      password: 123456
      driver-class-name: com.mysql.jdbc.Driver
      type: com.zaxxer.hikari.HikariDataSource
    #From data source
    secondary:
      url: jdbc:mysql://192.168.64.132:3307/testdb?serverTimezone=GMT & amp;seUnicode=true & amp;characterEncoding=UTF-8 & amp;useSSL=false & amp;allowMultiQueries=true & amp;autoReconnect= true &allowPublicKeyRetrieval=true
      username: root
      password: 123456
      driver-class-name: com.mysql.jdbc.Driver
    jpa:
      #Main jpa configuration
      primary:
        show-sql: true
        properties:
          hibernate:
            hbm2ddl:
              auto: update
            dialect: org.hibernate.dialect.MySQL8Dialect
      #Configure from jpa
      secondary:
        show-sql: true
        properties:
          hibernate:
            hbm2ddl:
              auto: update
            dialect: org.hibernate.dialect.MySQL8Dialect

3. Primary data source configuration

package com.xiaoxi.demo.config.primaryconfig;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

@Configuration
public class PrimaryDataSourceConfig {

    /**
     * Scan the configuration information starting with spring.datasource.primary
     *
     * @return data source configuration information
     */
    @Primary
    @Bean(name = "primaryDataSourceProperties")
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSourceProperties dataSourceProperties() {
        return new DataSourceProperties();
    }

    /**
     * Get the main database data source object
     *
     * @param dataSourceProperties injects a bean named primaryDataSourceProperties
     * @return data source object
     */
    @Primary
    @Bean(name = "primaryDataSource")
    public DataSource dataSource(@Qualifier("primaryDataSourceProperties") DataSourceProperties dataSourceProperties) {
        return dataSourceProperties.initializeDataSourceBuilder().build();
    }

    /**
     * This method is only used when you need to use the JdbcTemplate object
     *
     * @param dataSource injects a bean named primaryDataSource
     * @return data source JdbcTemplate object
     */
    @Primary
    @Bean(name = "primaryJdbcTemplate")
    public JdbcTemplate jdbcTemplate(@Qualifier("primaryDataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

4.Creation of main entity class

package com.xiaoxi.demo.entity.primaryentity;

import lombok.Data;

import javax.persistence.*;

@Data
@Entity // jpa-specific, must be added
@Table(name = "t_user")
public class PrimaryTbUserEntity {
    @Id //primary key id
    @GeneratedValue(strategy= GenerationType.IDENTITY)//Primary key generation strategy
    @Column(name="id") //Database field name
    privateInteger id;

    @Column(name = "uname")
    private String uname;
}

5. Main repository creation

package com.xiaoxi.demo.dao.primaryrepository;

import com.xiaoxi.demo.entity.primaryentity.PrimaryTbUserEntity;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository("primaryUserRepository")
@Primary
public interface PrimaryUserRepository extends JpaRepository<PrimaryTbUserEntity, Integer> {
}

6. Main jpa configuration

package com.xiaoxi.demo.config.primaryconfig;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
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;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        basePackages = PrimaryJpaConfig.REPOSITORY_PACKAGE,
        entityManagerFactoryRef = "primaryEntityManagerFactory",
        transactionManagerRef = "primaryTransactionManager"
)
public class PrimaryJpaConfig {
    static final String REPOSITORY_PACKAGE = "com.xiaoxi.demo.dao.primaryrepository";
    private static final String ENTITY_PACKAGE = "com.xiaoxi.demo.entity.primaryentity";

    /**
     * Scan the configuration information starting with spring.jpa.primary
     *
     * @return jpa configuration information
     */
    @Primary
    @Bean(name = "primaryJpaProperties")
    @ConfigurationProperties(prefix = "spring.jpa.primary")
    public JpaProperties jpaProperties() {
        return new JpaProperties();
    }

    /**
     * Get the main library entity management factory object
     *
     * @param primaryDataSource injects a data source named primaryDataSource
     * @param jpaProperties injects jpa configuration information named primaryJpaProperties
     * @param builder injects EntityManagerFactoryBuilder
     * @return entity management factory object
     */
    @Primary
    @Bean(name = "primaryEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(
            @Qualifier("primaryDataSource") DataSource primaryDataSource,
            @Qualifier("primaryJpaProperties") JpaProperties jpaProperties,
            EntityManagerFactoryBuilder builder
    ) {
        return builder
                //Set data source
                .dataSource(primaryDataSource)
                //Set jpa configuration
                .properties(jpaProperties.getProperties())
                //Set the entity package name
                .packages(ENTITY_PACKAGE)
                //Set the persistence unit name, which is used to specify the data source when the @PersistenceContext annotation obtains the EntityManager.
                .persistenceUnit("primaryPersistenceUnit").build();
    }

    /**
     * Get entity management object
     *
     * @param factory injects a bean named primaryEntityManagerFactory
     * @return entity management object
     */
    @Primary
    @Bean(name = "primaryEntityManager")
    public EntityManager entityManager(@Qualifier("primaryEntityManagerFactory") EntityManagerFactory factory) {
        return factory.createEntityManager();
    }

    /**
     * Get the main database transaction management object
     *
     * @param factory injects a bean named primaryEntityManagerFactory
     * @return transaction management object
     */
    @Primary
    @Bean(name = "primaryTransactionManager")
    public PlatformTransactionManager transactionManager(@Qualifier("primaryEntityManagerFactory") EntityManagerFactory factory) {
        return new JpaTransactionManager(factory);
    }
}

7. Configure from data source

package com.xiaoxi.demo.config.secondaryconfig;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

@Configuration
public class SecondaryDataSourceConfig {
    /**
     * Scan the configuration information starting with spring.datasource.secondary
     *
     * @return data source configuration information
     */
    @Bean(name = "secondaryDataSourceProperties")
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSourceProperties dataSourceProperties() {
        return new DataSourceProperties();
    }

    /**
     * Get the secondary data source object
     *
     * @param dataSourceProperties injects a bean named secondaryDataSourceProperties
     * @return data source object
     */
    @Bean("secondaryDataSource")
    public DataSource dataSource(@Qualifier("secondaryDataSourceProperties") DataSourceProperties dataSourceProperties) {
        return dataSourceProperties.initializeDataSourceBuilder().build();
    }

    /**
     * This method is only used when you need to use the JdbcTemplate object
     *
     * @param dataSource injects a bean named secondaryDataSource
     * @return data source JdbcTemplate object
     */
    @Bean(name = "secondaryJdbcTemplate")
    public JdbcTemplate jdbcTemplate(@Qualifier("secondaryDataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

8. Configure from jpa

package com.xiaoxi.demo.config.secondaryconfig;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
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;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        basePackages = SecondaryJpaConfig.REPOSITORY_PACKAGE,
        entityManagerFactoryRef = "secondaryEntityManagerFactory",
        transactionManagerRef = "secondaryTransactionManager"
)
public class SecondaryJpaConfig {

    static final String REPOSITORY_PACKAGE = "com.xiaoxi.demo.dao.secondaryrepository";
    private static final String ENTITY_PACKAGE = "com.xiaoxi.demo.entity.secondaryentity";

    /**
     * Scan spring.jpa.secondary
     *
     * @return jpa configuration information
     */
    @Bean(name = "secondaryJpaProperties")
    @ConfigurationProperties(prefix = "spring.jpa.secondary")
    public JpaProperties jpaProperties() {
        return new JpaProperties();
    }

    /**
     * Get the secondary library entity management factory object
     *
     * @param secondaryDataSource injects a data source named secondaryDataSource
     * @param jpaProperties injects jpa configuration information named secondaryJpaProperties
     * @param builder injects EntityManagerFactoryBuilder
     * @return entity management factory object
     */
    @Bean(name = "secondaryEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(
            @Qualifier("secondaryDataSource") DataSource secondaryDataSource,
            @Qualifier("secondaryJpaProperties") JpaProperties jpaProperties,
            EntityManagerFactoryBuilder builder
    ) {
        return builder
                //Set data source
                .dataSource(secondaryDataSource)
                //Set jpa configuration
                .properties(jpaProperties.getProperties())
                //Set the entity package name
                .packages(ENTITY_PACKAGE)
                //Set the persistence unit name, which is used to specify the data source when the @PersistenceContext annotation obtains the EntityManager.
                .persistenceUnit("secondaryPersistenceUnit").build();
    }

    /**
     * Get entity management object
     *
     * @param factory injects a bean named secondaryEntityManagerFactory
     * @return entity management object
     */
    @Bean(name = "secondaryEntityManager")
    public EntityManager entityManager(@Qualifier("secondaryEntityManagerFactory") EntityManagerFactory factory) {
        return factory.createEntityManager();
    }

    /**
     * Get the main database transaction management object
     *
     * @param factory injects a bean named secondaryEntityManagerFactory
     * @return transaction management object
     */
    @Bean(name = "secondaryTransactionManager")
    public PlatformTransactionManager transactionManager(@Qualifier("secondaryEntityManagerFactory") EntityManagerFactory factory) {
        return new JpaTransactionManager(factory);
    }
}

9. Configuration from entity class

package com.xiaoxi.demo.entity.secondaryentity;

import lombok.Data;

import javax.persistence.*;

@Data
@Entity // jpa-specific, must be added
@Table(name = "t_user")
public class SecondaryTbUserEntity {
        @Id //primary key id
        @GeneratedValue(strategy= GenerationType.IDENTITY)//Primary key generation strategy
        @Column(name="id") //Database field name
        privateInteger id;

        @Column(name = "uname")
        private String name;
}

10. Create from repository

package com.xiaoxi.demo.dao.secondaryrepository;

import com.xiaoxi.demo.entity.secondaryentity.SecondaryTbUserEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository("secondaryUserRepository")
public interface SecondaryUserRepository extends JpaRepository<SecondaryTbUserEntity, Integer> {
}

11. Configure from jpa

package com.xiaoxi.demo.config.secondaryconfig;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
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;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        basePackages = SecondaryJpaConfig.REPOSITORY_PACKAGE,
        entityManagerFactoryRef = "secondaryEntityManagerFactory",
        transactionManagerRef = "secondaryTransactionManager"
)
public class SecondaryJpaConfig {

    static final String REPOSITORY_PACKAGE = "com.xiaoxi.demo.dao.secondaryrepository";
    private static final String ENTITY_PACKAGE = "com.xiaoxi.demo.entity.secondaryentity";

    /**
     * Scan spring.jpa.secondary
     *
     * @return jpa configuration information
     */
    @Bean(name = "secondaryJpaProperties")
    @ConfigurationProperties(prefix = "spring.jpa.secondary")
    public JpaProperties jpaProperties() {
        return new JpaProperties();
    }

    /**
     * Get the secondary library entity management factory object
     *
     * @param secondaryDataSource injects a data source named secondaryDataSource
     * @param jpaProperties injects jpa configuration information named secondaryJpaProperties
     * @param builder injects EntityManagerFactoryBuilder
     * @return entity management factory object
     */
    @Bean(name = "secondaryEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(
            @Qualifier("secondaryDataSource") DataSource secondaryDataSource,
            @Qualifier("secondaryJpaProperties") JpaProperties jpaProperties,
            EntityManagerFactoryBuilder builder
    ) {
        return builder
                //Set data source
                .dataSource(secondaryDataSource)
                //Set jpa configuration
                .properties(jpaProperties.getProperties())
                //Set the entity package name
                .packages(ENTITY_PACKAGE)
                //Set the persistence unit name, which is used to specify the data source when the @PersistenceContext annotation obtains the EntityManager.
                .persistenceUnit("secondaryPersistenceUnit").build();
    }

    /**
     * Get entity management object
     *
     * @param factory injects a bean named secondaryEntityManagerFactory
     * @return entity management object
     */
    @Bean(name = "secondaryEntityManager")
    public EntityManager entityManager(@Qualifier("secondaryEntityManagerFactory") EntityManagerFactory factory) {
        return factory.createEntityManager();
    }

    /**
     * Get the main database transaction management object
     *
     * @param factory injects a bean named secondaryEntityManagerFactory
     * @return transaction management object
     */
    @Bean(name = "secondaryTransactionManager")
    public PlatformTransactionManager transactionManager(@Qualifier("secondaryEntityManagerFactory") EntityManagerFactory factory) {
        return new JpaTransactionManager(factory);
    }
}

12. Test

package com.xiaoxi.demo.controllerr;

import com.alibaba.fastjson2.JSON;
import com.xiaoxi.demo.dao.primaryrepository.PrimaryUserRepository;
import com.xiaoxi.demo.dao.secondaryrepository.SecondaryUserRepository;
import com.xiaoxi.demo.entity.primaryentity.PrimaryTbUserEntity;
import com.xiaoxi.demo.entity.secondaryentity.SecondaryTbUserEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

@RestController
public class TestMutiDataSource {

    @Autowired
    PrimaryUserRepository primaryUserRepository;

    @Autowired
    @Qualifier("secondaryUserRepository")
    SecondaryUserRepository secondaryUserRepository;

    @GetMapping("/test")
    public String TestMutiDataSource() {
        Map<String, String> re = new HashMap<>();
        Optional<PrimaryTbUserEntity> byId = primaryUserRepository.findById(1);
        if(byId.isPresent()) {
            re.put("Main database data", JSON.toJSONString(byId.get()));
        }
        Optional<SecondaryTbUserEntity> byIdSecondary = secondaryUserRepository.findById(2);
        if(byIdSecondary.isPresent()) {
            re.put("data from the database", JSON.toJSONString(byIdSecondary.get()));
        }
        return JSON.toJSONString(re);
    }
}

Print:
 {
   "Data from the database": "{"id":2,"name":"lisi4"}",
   "Main database data": "{"id":1,"uname":"zhang3"}"
}

Summary:

To configure multiple data sources in jpa is to configure multiple repositories. Each repository corresponds to different data sources.