数据物理隔离

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")

results matching ""

    No results matching ""