博客
关于我
Spring Boot + Mybatis 配合 AOP 和注解实现动态数据源切换配置
阅读量:796 次
发布时间:2023-03-22

本文共 7124 字,大约阅读时间需要 23 分钟。

Spring Boot 多数据源配置实践指南

随着应用用户数量的不断增加,系统处理请求的并发压力也在上升。单一数据库逐渐暴露出性能瓶颈,这时候配置多个数据源成为一种有效的解决方案。Spring Boot 提供了丰富的功能,能够帮助开发者灵活配置多数据源。本文将详细介绍如何结合 AOP 和注解实现动态数据源切换。

数据库准备

首先,我们需要准备两个数据库,分别存储不同的数据。以下是数据库的建表语句和数据插入示例:

CREATE TABLE sys_user (
user_id INT PRIMARY KEY AUTO_INCREMENT,
user_name VARCHAR(255) NOT NULL,
user_age INT DEFAULT 0
);
CREATE TABLE sys_user2 (
user_id INT PRIMARY KEY AUTO_INCREMENT,
user_name VARCHAR(255) NOT NULL,
user_age INT DEFAULT 0
);
INSERT INTO sys_user (user_name, user_age) VALUES ('张三', 25);
INSERT INTO sys_user2 (user_name, user_age) VALUES ('李四', 30);

环境配置

新建一个 Spring Boot 2.1.7.RELEASE 项目,添加以下依赖:

mysql
mysql-connector-java
8.0.32
org.springframework.boot
spring-boot-starter-jdbc
org.springframework
spring-aop
5.1.5.RELEASE
org.aspectj
aspectjweaver
1.9.2

代码实现

application.properties 中配置数据源:

spring.datasource.primary.jdbc-url=jdbc:mysql://localhost:3306/testdatasource1?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
spring.datasource.primary.username=root
spring.datasource.primary.password=root
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.secondary.jdbc-url=jdbc:mysql://localhost:3306/testdatasource2?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
spring.datasource.secondary.username=root
spring.datasource.secondary.password=root
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver

创建 DynamicDataSourceConfig 配置类:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
@Configuration
public class DynamicDataSourceConfig {
@Autowired
private DataSourceProperties dataSourceProperties;
@Bean(name = "PrimaryDataSource")
@Primary
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource getDateSource1() {
return DataSourceBuilder.create().build();
}
@Bean(name = "SecondaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource getDateSource2() {
return DataSourceBuilder.create().build();
}
@Bean(name = "dynamicDataSource")
public DynamicDataSource dataSource(@Qualifier("PrimaryDataSource") DataSource primary,
@Qualifier("SecondaryDataSource") DataSource secondary) {
Map
targetDataSource = new HashMap<>();
targetDataSource.put(DataSourceType.DataBaseType.Primary, primary);
targetDataSource.put(DataSourceType.DataBaseType.Secondary, secondary);
DynamicDataSource dataSource = new DynamicDataSource();
dataSource.setTargetDataSources(targetDataSource);
dataSource.setDefaultTargetDataSource(primary);
return dataSource;
}
@Bean(name = "SqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapping/*/*.xml"));
return bean.getObject();
}
}

自定义 DynamicDataSource 类:

import org.springframework.boot.jdbc.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
DataSourceType.DataBaseType dataType = DataSourceType.getDataBaseType();
return dataType;
}
}

DataSourceType 枚举类:

public enum DataSourceType {
TYPE(new ThreadLocal<>());
private static final ThreadLocal
TYPE;
DataSourceType() {
TYPE.set(this);
}
public static void setDataBaseType(DataSourceType dataType) {
if (dataType == null) {
throw new NullPointerException();
}
TYPE.set(dataType);
}
public static DataSourceType getDataBaseType() {
DataSourceType dataType = TYPE.get() == null ? Primary : TYPE.get();
return dataType;
}
public static void clearDataBaseType() {
TYPE.remove();
}
}

Mapper 接口

编写 mapper 接口,并添加自定义注解:

@Component
public interface PrimaryUserMapper {
@DataSource
List
findAll();
}
@Component
public interface SecondaryUserMapper {
@DataSource("secondary")
List
findAll();
}

AOP 实现

创建 DataSourceAop 类:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class DataSourceAop {
@Before("execution(*com.example.controller.UserController.primary(..))")
public void setDataSource2test01() {
System.err.println("Primary业务");
DataSourceType.setDataBaseType(DataSourceType.DataBaseType.Primary);
}
@Before("execution(*com.example.controller.UserController.secondary(..))")
public void setDataSource2test02() {
System.err.println("Secondary业务");
DataSourceType.setDataBaseType(DataSourceType.DataBaseType.Secondary);
}
}

测试

启动项目,访问 http://localhost:8080/primaryhttp://localhost:8080/secondary,验证数据源切换是否正确。

注解实现

创建自定义注解 DataSource

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
String value() default "primary";
}

创建 DynamicDataSourceAspect

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class DynamicDataSourceAspect {
private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);
@Before("@annotation(dataSource)")
public void changeDataSource(JoinPoint point, DataSource dataSource) throws Throwable {
String value = dataSource.value();
if (value.equals("primary")) {
DataSourceType.setDataBaseType(DataSourceType.DataBaseType.Primary);
} else if (value.equals("secondary")) {
DataSourceType.setDataBaseType(DataSourceType.DataBaseType.Secondary);
} else {
DataSourceType.setDataBaseType(DataSourceType.DataBaseType.Primary);
}
}
@After("@annotation(dataSource)")
public void restoreDataSource(JoinPoint point, DataSource dataSource) throws Throwable {
DataSourceType.clearDataBaseType();
}
}

总结

通过以上配置,开发者可以灵活管理多个数据源,动态切换数据源类型。这种方法不仅适用于方法级别,还可以扩展到类级别,实现更复杂的数据源管理策略。希望这篇文章能为您的项目带来帮助!

转载地址:http://esqfk.baihongyu.com/

你可能感兴趣的文章
Objective-C实现环形缓冲区(附完整源码)
查看>>
Objective-C实现生产者和消费者问题(附完整源码)
查看>>
Objective-C实现生产者消费者问题(附完整源码)
查看>>
Objective-C实现生成 Mandelbrot 曼德勃罗集图像算法 (附完整源码)
查看>>
Objective-C实现生成崩溃dump文件 (附完整源码)
查看>>
Objective-C实现生成数组的所有不同排列算法(附完整源码)
查看>>
Objective-C实现生成正态分布数据(附完整源码)
查看>>
Objective-C实现生成随机高斯分布(附完整源码)
查看>>
Objective-C实现用 PIL 改变对比度算法(附完整源码)
查看>>
Objective-C实现用二维数组实现矩阵的转置(附完整源码)
查看>>
Objective-C实现用半正弦公式计算两个坐标之间的距离算法 (附完整源码)
查看>>
Objective-C实现用卡方解密凯撒算法(附完整源码)
查看>>
Objective-C实现用蒙特卡洛方法计算圆周率PI算法(附完整源码)
查看>>
Objective-C实现用递归计算给定数的幂算法(附完整源码)
查看>>
Objective-C实现由伪栈表示的队列算法(附完整源码)
查看>>
Objective-C实现由列表表示的队列算法(附完整源码)
查看>>
Objective-C实现电子词典(附完整源码)
查看>>
Objective-C实现电脑锁屏(附完整源码)
查看>>
Objective-C实现相等的每月分期付款算法(附完整源码)
查看>>
Objective-C实现真值表(附完整源码)
查看>>