数据物理隔离
1、需求
在服务中引入多个数据源,按照请求头中携带的租户标志分别访问不同数据源,保证不通租户之间的数据物理隔离
2、方案
使用dynamic-datasource-spring-boot-starter框架,可以实现动态数据源
步骤一
pom框架引入
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.5.0</version>
</dependency>
步骤二
ym数据源l配置
spring:
datasource:
dynamic:
primary: first
datasource:
first:
url: jdbc:mysql://47.92.251.153:3306/first?useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
username: taoge
password: *******
hikari:
minimum-idle: 5
maximum-pool-size: 15
auto-commit: true
idle-timeout: 30000
pool-name: MyHikariCP
connection-timeout: 30000
connection-test-query: SELECT 1
second:
url: jdbc:mysql://47.92.251.153:3306/second?useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
username: taoge
password: *******
hikari:
minimum-idle: 5
maximum-pool-size: 15
auto-commit: true
idle-timeout: 30000
pool-name: MyHikariCP
connection-timeout: 30000
connection-test-query: SELECT 1
步骤三
拦截器配置+ThreadLocal
可以用于处理请求头的租户标志,并且可以通过ThreadLocal获取当前线程的租户标志
public class TenementFlagContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
/**
* 设置租户标志
*
* @param tenementFlag
*/
public static void setTenementFlag(String tenementFlag) {
contextHolder.set(tenementFlag);
}
/**
* 获取当前线程的租户标志
*
* @return
*/
public static String getTenementFlag() {
return contextHolder.get();
}
/**
* 删除当前线程租户标志
*/
public static void clearTenementFlag() {
contextHolder.remove();
}
}
拦截器配置
@Slf4j
@Component
public class TenementFlagInterceptor implements HandlerInterceptor {
private String iv;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String tenementFlag = request.getHeader("tenementFlag");
if (StringUtils.isNotEmpty(tenementFlag)) {
TenementFlagEnum flagEnum = TenementFlagEnum.getTenementFlag(tenementFlag);
TenementFlagContextHolder.setTenementFlag(flagEnum.getTenementFlag());
} else {
TenementFlagContextHolder.setTenementFlag(TenementFlagEnum.DEFAULT.getTenementFlag());
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
TenementFlagContextHolder.clearTenementFlag();
}
}
步骤四
动态数据源
使用框架自带的DS注解,可以在方法、类上添加,可以支持固定值、方法参数获取、请求头获取等方式
一般用在service类上
@DS("#header.tenementFlag")