How to use the same Mapper class in multiple data sources with Spring Boot + MyBatis

Introduction

In the case I experienced Since we built a system using different data sources and the same table definition, We will share the know-how at that time.

Data source definition

The driver uses "Oracle", but please modify it appropriately according to your environment.

application.yml


spring:
  datasource:
    #Data source A
    alpha:
      jdbc-url: jdbc:oracle:thin:@localhost:1521/XEPDB1
      username: sample_a
      password: sample_a
      driverClassName: oracle.jdbc.OracleDriver
    #Data source B
    beta:
      jdbc-url: jdbc:oracle:thin:@localhost:1521/XEPDB1
      username: sample_b
      password: sample_b
      driverClassName: oracle.jdbc.OracleDriver

MyBatis settings

DataSourceConfig.java


package com.example;

@Configuration
@MapperScan(basePackages = { "com.example.mapper" }, sqlSessionTemplateRef = "sqlSessionTemplate") // ①
public class DataSourceConfig {

    @Bean(name = "alphaDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.alpha")
    public DataSource alphaDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "betaDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.beta")
    public DataSource betaDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean("dynamicDataSource")
    public DynamicRoutingDataSourceResolver dynamicDataSource(@Qualifier("alphaDataSource") DataSource alphaDataSource, @Qualifier("betaDataSource") DataSource betaDataSource) {
        Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
        targetDataSources.put(DataSourceType.ALPHA, alphaDataSource);
        targetDataSources.put(DataSourceType.BETA, betaDataSource);

        //Dynamic change of data source
        DynamicRoutingDataSourceResolver resolver = new DynamicRoutingDataSourceResolver();
        resolver.setTargetDataSources(targetDataSources);
        resolver.setDefaultTargetDataSource(alphaDataSource);

        return resolver;
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DynamicRoutingDataSourceResolver resolver) throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();

        // ②
        factoryBean.setDataSource(resolver);
        factoryBean.setMapperLocations("Mapper XML path");
        factoryBean.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);

        return factoryBean.getObject();
    }

    // ...abridgement
}

①: Set an alias for the commonly used Mapper class (2): AutoConfigure is disabled for multi-data sources, so set it manually.

Data source switching

Define a partition value to determine the reference data source.

public enum DataSourceType {
    ALPHA, BETA
}

The division value is held for each thread.

DataSourceContextHolder.java


public class DataSourceContextHolder {

    private static ThreadLocal<DataSourceType> contextHolder = new ThreadLocal<DataSourceType>();

    public static void setDataSourceType(DataSourceType dataSourceType) {
        contextHolder.set(dataSourceType);
    }

    public static DataSourceType getDataSourceType() {
        return contextHolder.get();
    }

    public static void clear() {
        contextHolder.remove();
    }
}

Obtain the classification value for determining the reference data source. From the data source set in DataSourceConfig.dynamicDataSource with this indicator value Determine the data source to actually refer to.

DynamicRoutingDataSourceResolver.java


public class DynamicRoutingDataSourceResolver extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSourceType();
    }
}

how to use

Let's set the DataSourceType via the DataSourceContextHolder. If you want to define it as cross-sectional processing, use AOP etc. to switch the data source.

DataSourceContextHolder.setDataSourceType(DataSourceType.ALPHA);

Recommended Posts

How to use the same Mapper class in multiple data sources with Spring Boot + MyBatis
How to use MyBatis2 (iBatis) with Spring Boot 1.4 (Spring 4)
How to use built-in h2db with spring boot
How to use CommandLineRunner in Spring Batch of Spring Boot
How to call and use API in Java (Spring Boot)
How to use Java enums (Enum) in MyBatis Mapper XML
Mapping to a class with a value object in How to MyBatis
How to use Lombok in Spring
How to use Spring Data JDBC
How to use the wrapper class
How to use MyBatis Mapper annotation
How to use ModelMapper (Spring boot)
How to use MinIO with the same function as S3 Use docker-compose
How to call multiple names at once in the same category
[Java] How to use the File class
[Java] How to use the HashMap class
[Processing × Java] How to use the class
[Java] How to use the Calendar class
How to apply thymeleaf changes to the browser immediately with #Spring Boot + maven
How to read Body of Request multiple times with Spring Boot + Spring Security
Until data acquisition with Spring Boot + MyBatis + PostgreSQL
How to use Spring Boot session attributes (@SessionAttributes)
How to add a classpath in Spring Boot
FactoryBot Register multiple data with the same model
How to bind to property file in Spring Boot
[JAVA] [Spring] [MyBatis] Use IN () with SQL Builder
How to define multiple orm.xml in Spring4, JPA2.1
[Spring Boot] How to refer to the property file
[Rails] How to register multiple records in the intermediate table with many-to-many association
How to store an object in PostgreSQL as JSON with MyBatis (Mapper XML)
How to perform UT with Excel as test data with Spring Boot + JUnit5 + DBUnit
How to set environment variables in the properties file of Spring boot application
How to change the action with multiple submit buttons
How to use Z3 library in Scala with Eclipse
How to create a Spring Boot project in IntelliJ
Organized how to interact with the JDK in stages
How to use JDD library in Scala with Eclipse
[Swift] Use UserDefaults to save data in the app
How to boot by environment with Spring Boot of Maven
How to use In-Memory Job repository in Spring Batch
How to use git with the power of jgit in an environment without git commands
`bind': Address already in use --bind (2) for 127.0.0.1:3000 (Errno :: EADDRINUSE) How to deal with the error
Form and process file and String data at the same time with Spring Boot + Java
Summary of how to use the proxy set in IE when connecting with Java
I want to get the information of the class that inherits the UserDetails class of the user who is logged in with Spring Boot.
How to use the getter / setter method (in object orientation)
How to change application.properties settings at boot time in Spring boot
Use collection_select to pull down the data stored in Active_Hash
How to use JSON data in WebSocket communication (Java, JavaScript)
How to pass an object to Mapper in MyBatis without arguments
How to write in Model class when you want to save binary data in DB with PlayFramework
How to create a placeholder part to use in the IN clause
How to use java class
Uppercase only the specified range with substring. (How to use substring)
Flow until output table data to view with Spring Boot
How to add the same Indexes in a nested array
Use thymeleaf3 with parent without specifying spring-boot-starter-parent in Spring Boot
Use Spring JDBC with Spring Boot
wsimport error handling (A class / interface with the same name "xxx" is already in use)
Let's find out how to receive in Request Body with REST API of Spring Boot
Use @ControllerAdvice, @ExceptionHandler, HandlerExceptionResolver in Spring Boot to catch exceptions