数据库读取数据源配置实现动态数据源

906 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第7天,点击查看活动详情

概述

项目中整合多数据源时,一般是通过读取配置文件中的数据源信息创建数据源 放到AbstractRoutingDataSource的targetDataSources的map中, 然后通过AbstractRoutingDataSource获取实际需要的数据源。

当项目中需要整合的数据源特别多的时候,比如:8个、16个、32个数据库等, 这个时候配置文件就会变得比较臃肿,而且现在主流的是微服务架构, 可能一套服务有多个模块,如果是通过配置文件进行配置,那么需要 修改的配置文件相对较多,这种情况可以通过数据库进行配置数据源 或者是通过配置中心进行配置。

下面将演示通过数据库配置所有的数据源,服务只需要配置默认的数据源, 通过默认的数据源读取配置的多数据源,然后创建数据源实例,最后将 创建的数据源实例放在AbstractRoutingDataSource中。

环境说明

  • spring boot
  • mysql
  • mybatis-plus
  • spring-aop
  • druid
  • redis

项目目录结构

  • controller: 存放接口类
  • service: 存放服务类
  • mapper: 存放操作数据库的mapper接口
  • model: 存放数据库表实体类
  • vo: 存放返回给前端的视图类

  • context: 线程公共上下文
  • config: 数据源配置信息
  • annotation: 实现动态数据源加载自定义注解
  • aop: 实现动态数据源设置切面类
  • util: 工具类
  • constants: 常量类

关键类说明

  • SpringContextUtils: 获取手动获取Spring容器中的bean, 包含ApplicationContext属性
  • DynamicContextHolder: 当前线程持有的数据源key, 包含ThreadLocal属性
  • DataSourceCachePool: 数据源缓存池
  • DynamicDataSource: 动态数据源配置类
  • DynamicDataSourceConfig: 数据源配置类
  • DynamicDataSourceFactory: 数据源工厂
  • DataSourceRoute: 动态设置数据源key注解
  • DbKey: 指定数据源key参数注解
  • DynamicDataSource: 指定动态数据源方法注解
  • DataSourceAspect: 动态数据源注解切面
  • DynamicDataSourceAspect: 指定动态数据源切面
  • DynamicDBUtil: 动态数据源工具

image.png

简要设计

1、设计数据源配置表,表结构就按实际配置数据源所需要的属性,可以参考DataSourceProperties进行字段设计

CREATE TABLE `t_dynamic_datasource` (
     `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
     `datasource_name` varchar(20) DEFAULT '' COMMENT '数据源名称',
     `datasource_url` varchar(200) DEFAULT '' COMMENT '数据源url',
     `db_driver` varchar(200) DEFAULT '' COMMENT '数据源url',
     `datasource_account` varchar(50) DEFAULT '' COMMENT '数据源帐号',
     `datasource_password` varchar(64) DEFAULT '' COMMENT '数据源密码',
     `remark` varchar(200) DEFAULT NULL COMMENT '备注',
     `is_show_type` tinyint(1) DEFAULT NULL COMMENT '数据源可见类型(1-全部人可见,2-部分人可见)',
     `datasource_type` tinyint(1) DEFAULT NULL COMMENT '默认mysql,暂时只支持mysql',
     `update_name` varchar(20) DEFAULT '' COMMENT '更新人',
     `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
     `create_code` int(11) unsigned DEFAULT '0' COMMENT '创建人工号',
     `create_name` varchar(20) DEFAULT '' COMMENT '创建人',
     `update_code` int(11) unsigned DEFAULT '0' COMMENT '更新人工号',
     `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
     `deleted_flag` tinyint(1) DEFAULT '0' COMMENT '是否删除',
     PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='数据源 ';

构建默认的数据源作为AbstractRoutingDataSource的defaultTargetDataSource属性的值,默认的数据源就是上一步创建配置表的数据库, 这个数据源的作用就是读取配置在其数据库表中其他数据源配置信息

3、标注有@DataSourceRoute注解的方法或者类被请求时,先通过AOP设置对应的数据源到AbstractRoutingDataSource中

4、动态数据源构建工具首先从本地数据源缓存池中查找,找到直接使用放入AbstractRoutingDataSource, 未找到再从缓存或者数据库中直接读取数据源配置信息,然后构建数据源

5、构建的动态数据源存放到本地缓存池中一份,以及Spring抽象出的AbstractRoutingDataSource数据源一份

6、数据源准备完成后,在将动态数据源的kye放入到本地线程的持有对象中。这个持有对象包含一个ThreadLocal变量,线程key就是存放其中

7、动态数据源的key除了可以通过自己的动态数据源注解进行设置外,也可以通过自定义注解表示请求参数进行动态的设置数据源key

image-20220731225438253.png

总结

共有两种方式设置动态数据源key。第一种通过动态数据源注解的方式设置数据源key, 该方式是在项目加载时就已经固定了,不是特别灵活。第二种是通过方法参数传递数据源key, 通过自定义注解表示传入的参数是数据源key,这种方式同样地请求可以通过参数实现每次请求 都可以动态的改变数据源。

请求流程图:

dynimid-datasource-class-lab-.png

项目地址