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!