SoFunction
Updated on 2025-04-14

Spring Boot 3.4.0 Combined with Mybatis-plus to implement a complete solution for dynamic data sources

Preface

In actual enterprise-level application development, the demand for multiple data sources is very common. This article will introduce in detail how to combine Mybatis-plus to implement dynamic data source switching function in Spring Boot 3.4.0 project.

1. Environmental preparation

First make sure your development environment meets the following requirements:

  • JDK 17+
  • Spring Boot 3.4.0
  • Mybatis-plus 3.5.3.1+
  • Maven 3.6.3+

2. Project configuration

1. Add dependencies

existAdd the following dependencies to:

<dependencies>
    <!-- Spring Boot Starter -->
    <dependency>
        <groupId></groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Mybatis-plus -->
    <dependency>
        <groupId></groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.3.1</version>
    </dependency>
    <!-- Database Driver -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <!-- Other tools -->
    <dependency>
        <groupId></groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

2. Configuration file

existConfigure multiple data sources:

spring:
  datasource:
    master:
      driver-class-name: 
      url: jdbc:mysql://localhost:3306/master_db?useSSL=false&serverTimezone=UTC
      username: root
      password: 123456
    slave1:
      driver-class-name: 
      url: jdbc:mysql://localhost:3306/slave1_db?useSSL=false&serverTimezone=UTC
      username: root
      password: 123456
    slave2:
      driver-class-name: 
      url: jdbc:mysql://localhost:3306/slave2_db?useSSL=false&serverTimezone=UTC
      username: root
      password: 123456

Implement dynamic data sources

1. Data source enumeration

public enum DataSourceType {
    MASTER("master"),
    SLAVE1("slave1"),
    SLAVE2("slave2");
    private final String name;
    DataSourceType(String name) {
         = name;
    }
    public String getName() {
        return name;
    }
}

2. Dynamic data source context

public class DynamicDataSourceContextHolder {
    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
    public static void setDataSourceType(String dataSourceType) {
        CONTEXT_HOLDER.set(dataSourceType);
    }
    public static String getDataSourceType() {
        return CONTEXT_HOLDER.get();
    }
    public static void clearDataSourceType() {
        CONTEXT_HOLDER.remove();
    }
}

3. Dynamic data source configuration

@Configuration
@MapperScan(basePackages = "")
public class DynamicDataSourceConfig {
    @Bean
    @ConfigurationProperties("")
    public DataSource masterDataSource() {
        return ().build();
    }
    @Bean
    @ConfigurationProperties(".slave1")
    public DataSource slave1DataSource() {
        return ().build();
    }
    @Bean
    @ConfigurationProperties(".slave2")
    public DataSource slave2DataSource() {
        return ().build();
    }
    @Bean
    public DataSource dynamicDataSource() {
        Map<Object, Object> targetDataSources = new HashMap<>();
        ((), masterDataSource());
        (DataSourceType.(), slave1DataSource());
        (DataSourceType.(), slave2DataSource());
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        (targetDataSources);
        (masterDataSource());
        return dynamicDataSource;
    }
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

4. Dynamic data source implementation

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return ();
    }
}

5. Custom annotations

@Target({, })
@Retention()
@Documented
public @interface DataSource {
    DataSourceType value() default ;
}

6. AOP sectional implementation

@Aspect
@Component
@Order(-1)
@Slf4j
public class DataSourceAspect {
    @Pointcut("@annotation()" +
            "|| @within()")
    public void dsPointCut() {
    }
    @Around("dsPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        DataSource dataSource = getDataSource(point);
        if (dataSource != null) {
            (().getName());
        }
        try {
            return ();
        } finally {
            ();
        }
    }
    private DataSource getDataSource(ProceedingJoinPoint point) {
        MethodSignature signature = (MethodSignature) ();
        DataSource dataSource = ((), );
        if (dataSource != null) {
            return dataSource;
        }
        return ((), );
    }
}

IV. Use examples

1. Service layer usage

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Override
    @DataSource()
    public User getMasterUser(Long id) {
        return (id);
    }
    @Override
    @DataSource(DataSourceType.SLAVE1)
    public User getSlave1User(Long id) {
        return (id);
    }
    @Override
    @DataSource(DataSourceType.SLAVE2)
    public User getSlave2User(Long id) {
        return (id);
    }
}

2. Controller layer call

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
    @GetMapping("/master/{id}")
    public User master(@PathVariable Long id) {
        return (id);
    }
    @GetMapping("/slave1/{id}")
    public User slave1(@PathVariable Long id) {
        return userService.getSlave1User(id);
    }
    @GetMapping("/slave2/{id}")
    public User slave2(@PathVariable Long id) {
        return userService.getSlave2User(id);
    }
}

5. Things to note

  • Transaction Management: Special attention should be paid to dynamic data source switching and transaction management. It is recommended not to switch data sources in transaction methods.
  • Connection pool configuration: Connection pool parameters can be configured separately for each data source
  • Performance considerations: Frequent switching of data sources may affect performance, and should be designed reasonably according to actual needs.
  • Exception handling: Do a good job in exception handling when data source switching fails

6. Summary

This article details the complete solution to implement dynamic data source switching in the Spring Boot 3.4.0 project in combination with Mybatis-plus. Through custom annotations and AOP sections, we can elegantly implement method-level data source switching to meet various needs in multi-data source scenarios.

This is the article about Spring Boot 3.4.0 combined with Mybatis-plus to implement a complete solution for dynamic data source. For more related Spring Boot Mybatis-plus dynamic data source content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!