需求说明
不同的用户角色在访问系统的时候,后台要根据角色切换不同的数据库用户名和密码。
你就说变不变态吧。。。。
环境说明
数据库:mysql8.0
jdk17
SpringBoot 2.7.6
mybatis plus 3.5.5
以下为代码讲解,可跳过自行拉取代码测试
代码
1、数据源上下文 Holder,存储当前线程的数据源标识
java
public class DataSourceContextHolder {
private static final ThreadLocal<UserType> CONTEXT_HOLDER = new ThreadLocal<>();
// 设置数据源标识
public static void setDataSourceType(UserType type) {
CONTEXT_HOLDER.set(type);
}
// 获取数据源标识
public static UserType getDataSourceType() {
return CONTEXT_HOLDER.get() == null ? UserType.USER : CONTEXT_HOLDER.get();
}
// 清除数据源标识(避免内存泄漏)
public static void clearDataSourceType() {
CONTEXT_HOLDER.remove();
}
}
2、动态数据源,根据ThreadLocal中的标识切换数据源
java
/**
* 动态数据源,根据ThreadLocal中的标识切换数据源
*
* @author smallNorth_Lee
* @since 2026/1/22
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
UserType dataSourceType = DataSourceContextHolder.getDataSourceType();
return dataSourceType == null ? UserType.ADMIN : dataSourceType;
}
}
3、数据源拦截器
这里说明一下,模拟的是从请求头获取用户的角色,实际场景中会出现,"用户没有登录我怎么知道他的角色??",这里登录的接口肯定要为公共接口,不然没得聊。
java
/**
* 数据源拦截器
*
* @author smallNorth_Lee
* @since 2026/1/22
*/
@Component
public class DataSourceInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// TODO 这里模拟用户角色,实际项目中可自行调整,登录的接口肯定为公共的数据源,其它查询的时候需要判断用户角色
String role = request.getHeader("role");
if (role == null){
role = "ADMIN";
}
String resLogger = "\n\n============== request Start ==============";
resLogger += "\n当前用户角色为 : " + role;
if (UserType.ADMIN.name().equals(role.toUpperCase())) {
resLogger += "\n使用的数据源为 : {ADMIN}";
DataSourceContextHolder.setDataSourceType(UserType.ADMIN);
} else if (UserType.USER.name().equals(role.toUpperCase())) {
resLogger += "\n使用的数据源为 : {USER}";
DataSourceContextHolder.setDataSourceType(UserType.USER);
}
resLogger += "\n============== request End ==============\n";
System.out.println(resLogger);
return true;
}
// 清理数据源
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
DataSourceContextHolder.clearDataSourceType();
}
}
4、数据源配置
yaml
server:
port: 2026
spring:
application:
name: dynamic-datasource
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/auth-center?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
user:
username: root
password: 123456
admin:
username: root
password: 123456
java
/**
* 数据源配置
*
* @author smallNorth_Lee
* @since 2026/1/22
*/
@Configuration
public class DataSourceConfig {
@Value("${spring.datasource.url}")
private String url;
@Value("${spring.datasource.driver-class-name}")
private String driverClassName;
@Value("${spring.datasource.admin.username}")
private String adminUsername;
@Value("${spring.datasource.admin.password}")
private String adminPassword;
@Bean("adminDataSource")
public DataSource adminDataSource() {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl(url);
dataSource.setUsername(adminUsername);
dataSource.setPassword(adminPassword);
dataSource.setDriverClassName(driverClassName);
dataSource.setMaximumPoolSize(10);
dataSource.setMinimumIdle(2);
return dataSource;
}
@Value("${spring.datasource.user.username}")
private String userUsername;
@Value("${spring.datasource.user.password}")
private String userPassword;
@Bean("userDataSource")
public DataSource userDataSource() {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl(url);
dataSource.setUsername(userUsername);
dataSource.setPassword(userPassword);
dataSource.setDriverClassName(driverClassName);
dataSource.setMaximumPoolSize(10);
dataSource.setMinimumIdle(2);
return dataSource;
}
@Bean("dynamicDataSource")
@Primary // 设置为默认数据源
public DataSource dynamicDataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
// 初始化数据源映射
Map<Object, Object> dataSourceMap = new HashMap<>();
dataSourceMap.put(UserType.ADMIN, adminDataSource());
dataSourceMap.put(UserType.USER, userDataSource());
// 设置数据源映射
dynamicDataSource.setTargetDataSources(dataSourceMap);
// 设置默认数据源
dynamicDataSource.setDefaultTargetDataSource(adminDataSource());
return dynamicDataSource;
}
// 事务管理
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dynamicDataSource());
}
}
5、MyBatisPlus 配置类
java
/**
* MyBatisPlus 配置类
*
* @author smallNorth_Lee
* @since 2026/1/22
*/
@Configuration
public class MyBatisPlusConfig {
@Resource
private DataSource dynamicDataSource;
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
@Bean
public MybatisSqlSessionFactoryBean sqlSessionFactory() {
MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
sqlSessionFactory.setDataSource(dynamicDataSource);
return sqlSessionFactory;
}
}
6、web配置,注册拦截器
java
/**
* web配置,注册拦截器
*
* @author smallNorth_Lee
* @since 2026/1/22
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new DataSourceInterceptor()).addPathPatterns("/**");
}
}
其它都是CRUD基础操作,可拉取代码测试哦,代码地址:一给我里giaogiao