springboot实现动态数据源切换

为什么需要切换数据源?

当数据量超过500万行时,数据库就要考虑分库分表和读写分离,有些业务背景需要动态切换数据库。
当controller层处理请求,需要在dao层代码执行之前能够将数据源换成我们想要执行操作的数据源。

底层原理

Springboot内置了一个AbstractRoutingDataSource,将所有数据源装入map,然后可以根据不同的key返回不同的数据源。当springboot开始执行连接数据库之前会执行determineCurrentLookupKey()方法,这个方法返回的数据将作为key去map中查找相应的数据源。

需求

根据不同的请求实现动态切换,查询不同的数据库。

实现步骤

  1. 创建springboot工程,准备 数据库 和 web相关的依赖
    在这里插入图片描述

  2. 准备两个数据库的表,在项目中创建对应的pojo实体类
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  3. 分别创建两个数据库对应的dao层、service层和controller层,核心启动类上需要添加包扫描MapperScan
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  4. 准备相关的数据源配置信息,在application.properties文件中设置
    在这里插入图片描述

  5. 创建数据源自动配置类,当容器启动时,创建对应的数据源bean对象
    在这里插入图片描述

  6. 创建AbstractRoutingDataSource的子类,当springboot想要获取数据源对象时,会执行determinCurrentLookUpKey()方法,获取想要的数据源,所以需要重写这个方法
    在这里插入图片描述
    先将返回值写成固定字符串,后续实现动态获取key,再进行修改。

  7. 在数据源自动配置类中添加AbstractRoutingDataSource子类bean的注入,当AbstractRoutingDataSource想要获取数据源时,会从它的成员变量中存的数据源的map集合中获取,所以需要给它注入包含两个数据源的map集合
    在这里插入图片描述

  8. 在核心启动类上需要添加@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class} ),排除默认的数据源
    在这里插入图片描述

  9. 如何实现动态获取key?
    每一个请求是一个单独的线程,将key存入当前线程的ThreadLocal里面。创建新的对象RoutingDataSourceContext,存在唯一的ThreadLocal对象,在构造函数中传入key,另外创建获取方法和关闭方法。
    在这里插入图片描述

  10. 在重写的determinCurrentLookUpKey()方法中调用RoutingDataSourceContext动态获取key的方法
    在这里插入图片描述11. 在controller层发起请求时获取创建对应的RoutingDataSourceContext对象,传入对应的key,后续springboot找AbstractRoutingDataSource中的数据源时,就会由传入的key查找对应的map中的数据源。
    在这里插入图片描述

  11. 测试
    在这里插入图片描述
    在这里插入图片描述
    总结:

  • 创建AbstractRoutingDataSource的子类,实现determinCurrentLookUpKey()方法
  • 生成两个数据源bean对象需要配置进该子类bean对象中,当需要获取到数据源时,会从该对象的map中获取数据源
  • 如何动态获取key --> 使用线程绑定的ThreadLocal,保证每次请求查找指定的数据源
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐