其他分享
首页 > 其他分享> > 路由组件构建方案(分库分表)V1

路由组件构建方案(分库分表)V1

作者:互联网

路由组件构建方案V1

实现效果:通过注解实现数据分散到不同库不同表的操作。
实现主要以下几部分:

  1. 数据源的配置和加载
  2. 数据源的动态切换
  3. 切点设置以及数据拦截
  4. 数据的插入

涉及的知识点:

  1. 分库分表相关概念
  2. 散列算法
  3. 数据源的切换
  4. AOP切面
  5. Mybatis拦截器

数据源的配置和加载

获取多个数据源我们肯定需要在yaml或者properties中进行配置。所以首先需要获取到配置信息;
定义配置文件中的库和表:

server:
  port: 8080
# 多数据源路由配置
router:
  jdbc:
    datasource:
      dbCount: 2
      tbCount: 4
      default: db00
      routerKey: uId
      list: db01,db02
      db00:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://xxxxx:3306/xxxx?useUnicode=true
        username: xxxx
        password: 111111
      db01:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://xxxxx:3306/xxxxx?useUnicode=true
        username: xxxxx
        password: 111111
      db02:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://xxxxx:3306/xxxx?useUnicode=true
        username: xxxxx
        password: 111111
mybatis:
  mapper-locations: classpath:/com/xbhog/mapper/*.xml
  config-location:  classpath:/config/mybatis-config.xml

为了实现并且使用自定义的数据源配置信息,启动开始的时候让SpringBoot定位位置。
首先类加载顺序:指定自动配置;

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.xbhog.db.router.config.DataSourceAutoConfig

针对读取这种自定义较大的信息配置,就需要使用到 org.springframework.context.EnvironmentAware 接口,来获取配置文件并提取需要的配置信息。

public class DataSourceAutoConfig implements EnvironmentAware {

    @Override
    public void setEnvironment(Environment environment){
        ......
    }
}

属性配置中的前缀需要跟路由组件中的属性配置:
这里设置成什么,在配置文件中就要设置成对应名字

String prefix = "router.jdbc.datasource.";

根据其前缀获取对应的库数量dbCount、表数量tbCount以及数据源信息dataSource;

//库的数量
dbCount = Integer.valueOf(environment.getProperty(prefix + "dbCount"));
//表的数量
tbCount = Integer.valueOf(environment.getProperty(prefix + "tbCount"));
//分库分表数据源
String dataSources = environment.getProperty(prefix + "list");

针对多数据源的存在,使用Map进行存储:Map<String,Map<String,Object>> daraSources;

for(String dbInfo : dataSources.split(",")){
    Map<String,Object> dataSourceProps = PropertyUtil.handle(environment, prefix + dbInfo, Map.class);
    dataSourceMap.put(dbInfo,dataSourceProps);
}

通过dataSource方法实现数据源的实例化:把基于从配置信息中读取到的数据源信息,进行实例化创建。
将获得的信息放到DynamicDataSource类(父类:DataSource)中进行实例化(setTargetDataSources,setDefaultTargetDataSource);
将我们自定义的数据源加入到Spring容器管理中。

//创建数据源
Map<Object, Object> targetDataSource = new HashMap<>();
//遍历数据源的key和value
for(String dbInfo : dataSourceMap.keySet()){
    Map<String, Object> objectMap = dataSourceMap.get(dbInfo);
    targetDataSource.put(dbInfo,new DriverManagerDataSource(objectMap.get("url").toString(),
            objectMap.get("username").toString(),objectMap.get("password").toString()));
}
//这是数据源
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setTargetDataSources(targetDataSource);
//defaultDataSourceConfig的输入点
dynamicDataSource.setDefaultTargetDataSource(new DriverManagerDataSource(defaultDataSourceConfig.get("url").toString(),
        defaultDataSourceConfig.get("username").toString(),defaultDataSourceConfig.get("password").toString()));
return dynamicDataSource;

到这里前置的配置都在spring中完成,后续是对数据的插入,也就是mybatis的操作:包含库表的随机计算和数据拦截器的实现。

动态切换数据源

路由切换的实现通过AbstractRoutingDataSource抽象类,该类充当了DataSource的路由中介, 在运行的时候, 根据某种key值来动态切换到真正的DataSource上。继承了AbstractDataSourceAbstractDataSource实现了DataSource;
AbstractRoutingDataSource根据方法determineTargetDataSource:

检索当前目标数据源。确定当前查找键,在targetDataSources映射中执行查找,必要时退回到指定的默认目标数据源。

protected DataSource determineTargetDataSource() {
    Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
    Object lookupKey = determineCurrentLookupKey();
    DataSource dataSource = this.resolvedDataSources.get(lookupKey);
    if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
        dataSource = this.resolvedDefaultDataSource;
    }
    if (dataSource == null) {
        throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
    }
    return dataSource;

标签:路由,icode9,构建方案,数据源,拦截器,数据,
来源: