前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >数据源管理 | 主从库动态路由,AOP模式读写分离

数据源管理 | 主从库动态路由,AOP模式读写分离

作者头像
知了一笑
发布2020-04-08 14:39:31
4700
发布2020-04-08 14:39:31
举报
文章被收录于专栏:知了一笑

一、多数据源应用

1、基础描述

在相对复杂的应用服务中,配置多个数据源是常见现象,例如常见的:配置主从数据库用来写数据,再配置一个从库读数据,这种读写分离模式可以缓解数据库压力,提高系统的并发能力和稳定性,执行效率。

2、核心API

在处理这种常见问题,要学会查询服务基础框架的API,说直白点就是查询Spring框架的API(工作几年,还没用过Spring之外的框架搭建环境),这种常用的业务模式,基本上Spring都提供了API支持。

核心API:AbstractRoutingDataSource

底层维护Map容器,用来保存数据源集合,提供一个抽象方法,实现自定义的路由策略。

代码语言:javascript
复制
@Nullable
private Map<Object, DataSource> resolvedDataSources;
@Nullable
protected abstract Object determineCurrentLookupKey();

补刀一句:为何框架的原理很难通过一篇文章看明白?因为使用的不多,基本意识没有形成,熟悉框架原理的基本要求:对框架的各种功能都熟悉,经常使用,自然而然的就明白了,盐大晒的久,咸鱼才够味。

二、数据源路由

1、数据源管理

配置两个数据源

代码语言:javascript
复制
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driverClassName: com.mysql.jdbc.Driver
    master:
      url: jdbc:mysql://localhost:3306/data_master
      username: root
      password: 123456
    slave:
      url: jdbc:mysql://localhost:3306/data_slave
      username: root
      password: 123456

从实际开发角度,这两个数据源需要配置主从复制流程,再基于安全角度,写库可以只给写权限,读库只给读权限。

Map容器加载

代码语言:javascript
复制
@Configuration
public class DruidConfig {
    // 忽略参数加载,源码中有
    @Bean
    @Primary
    public DataSource primaryDataSource() {
        Map<Object, Object> map = new HashMap<>();
        map.put("masterDataSource", masterDataSource());
        map.put("slaveDataSource", slaveDataSource());
        RouteDataSource routeDataSource = new RouteDataSource();
        routeDataSource.setTargetDataSources(map);
        routeDataSource.setDefaultTargetDataSource(masterDataSource());
        return routeDataSource ;
    }
    private DataSource masterDataSource() {
        return getDefDataSource(masterUrl,masterUsername,masterPassword);
    }
    private DataSource slaveDataSource() {
        return getDefDataSource(slaveUrl,slaveUsername,slavePassword);
    }
    private DataSource getDefDataSource (String url,String userName,String passWord){
        DruidDataSource datasource = new DruidDataSource();
        datasource.setDriverClassName(driverClassName);
        datasource.setUrl(url);
        datasource.setUsername(userName);
        datasource.setPassword(passWord);
        return datasource;
    }
}

这里的Map容器管理两个key,masterDataSource和slaveDataSource代表两个不同的库,使用不同的key即加载对应的库。

2、容器Key管理

使用ThreadLocal管理当前会会话中线程参数,存取使用极其方便。

代码语言:javascript
复制
public class RouteContext implements AutoCloseable {

    private static final ThreadLocal<String> threadLocal = new ThreadLocal<>();
    public static void setRouteKey (String key){
        threadLocal.set(key);
    }
    public static String getRouteKey() {
        String key = threadLocal.get();
        return key == null ? "masterDataSource" : key;
    }
    @Override
    public void close() {
        threadLocal.remove();
    }
}

3、路由Key实现

获取ThreadLocal中,当前数据源的key,适配相关联的数据源。

代码语言:javascript
复制
public class RouteDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return RouteContext.getRouteKey();
    }
}

三、读写分离

1、AOP思维

基于AOP的切面思想,不同的方法类型,去设置对应路由Key,这样就可以在业务逻辑执行之前,切换到不同的数据源。

代码语言:javascript
复制
Aspect
@Component
@Order(1)
public class ReadWriteAop {

    private static Logger LOGGER = LoggerFactory.getLogger(ReadWriteAop.class) ;

    @Before("execution(* com.master.slave.controller.*.*(..))")
    public void setReadDataSourceType() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String method = request.getRequestURI() ;
        boolean rwFlag = readOrWrite(method) ;
        if (rwFlag){
            RouteContext.setRouteKey("slaveDataSource");
        } else {
            RouteContext.setRouteKey("masterDataSource");
        }
        LOGGER.info("请求方法:"+method+";执行库:"+RouteContext.getRouteKey());
    }

    private String[] readArr = new String[]{"select","count","query","get","find"} ;
    private boolean readOrWrite (String method){
        for (String readVar:readArr) {
            if (method.contains(readVar)){
                return true ;
            }
        }
        return false ;
    }
}

常见的读取方法:select、count、query、get、find等等,方法的命名要遵循自定义的路由规则。

2、提供测试接口

控制层API

代码语言:javascript
复制
import com.master.slave.entity.User;
import com.master.slave.service.UserService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;

@RestController
public class UserController {

    @Resource
    private UserService userService ;

    @GetMapping("/selectById")
    public User selectById (@RequestParam("id") Integer id) {
        return userService.selectById(id) ;
    }

    @GetMapping("/insert")
    public String insert () {
        User user = new User("张三","write") ;
        userService.insert(user) ;
        return "success" ;
    }
}

服务实现

代码语言:javascript
复制
@Service
public class UserService {

    @Resource
    private UserMapper userMapper ;

    public User selectById (Integer id) {
        return userMapper.selectById(id) ;
    }

    public void insert (User user){
        userMapper.insert(user);
    }
}

这样数据源基于不同的类型方法就会一直的动态切换。

四、源代码地址

代码语言:javascript
复制
GitHub·地址
https://github.com/cicadasmile/data-manage-parent
GitEE·地址
https://gitee.com/cicadasmile/data-manage-parent
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-04-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 知了一笑 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、多数据源应用
    • 1、基础描述
      • 2、核心API
      • 二、数据源路由
        • 1、数据源管理
          • 2、容器Key管理
            • 3、路由Key实现
            • 三、读写分离
              • 1、AOP思维
                • 2、提供测试接口
                • 四、源代码地址
                相关产品与服务
                容器服务
                腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档