springboot 集成多数据源 二 通过继承AbstractRoutingDataSource来实现多数据源
一 实现原理
springboot从出生的时候,就考虑到多数据源的连接支持,其内置就提供了多数据源的抽象类AbstractRoutingDataSource,能过分析一些成熟的第三方多数据源开源组件,其实底层实现的也是或者类似这个原生的 AbstractRoutingDataSource的原理。本人就继续对上一篇中实现的非常粗糙的自定义多数据源类进行改造优化,来实现第二个版本。
二 实现细节
AbstractRoutingDataSource 实现数据源切换的原理是:
1. 在AbstractRoutingDataSource中,维护着三个重要的对象
TargetDataSources(我们设置的多个数据源)
resolvedDataSources(通过TargetDataSources生成的最终用于数据源切换的数据源列表,以键字对的形式存在)
DefaultTargetDataSource 默认使用的数据源是哪个
LookupKey,类似于我们上一篇中自定的ThreadLocal变量,用于查找最终切换的数据源的key
2. 用户发起请求,调用接口,通过LookupKey变量,通过 resolvedDataSources找到最终使用的 DeterminedTargetDataSource,通过获取到的这个ds的getconnection()方法,从而进行数据源的切换。
3. ORM通过获取到的dataSource进行数据库操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Primary; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; import org.springframework.stereotype.Component; import javax.sql.DataSource; import java.sql.SQLException; import java.util.HashMap; import java.util.Map; /** * 使用继承自 AbstractRoutingDataSource 来实现多数据源 * * 缺点:硬编码过多 只做为参考使用 */ @Component @Primary public class MyDynamicDataSourceTwo extends AbstractRoutingDataSource { /**用于全局切换数据源的标识**/ public static ThreadLocal<String> name = new ThreadLocal<>(); /** * 注入我们准备好的两个ds,准备进行数据源切换使用 * * @return * @throws SQLException */ @Autowired private DataSource ds1; @Autowired private DataSource ds2; /** * 这一部是返回数据查找时的键值 * @return */ @Override protected Object determineCurrentLookupKey() { System.out.println( "切换数据库为:" +CommonConstant.ds_LookupKey.get()); return CommonConstant.ds_LookupKey.get(); } @Override public void afterPropertiesSet() { //设置 TargetDataSources Map<Object, Object> targetDataSources= new HashMap<>(); targetDataSources.put( "w" ,ds1); targetDataSources.put( "r" ,ds2); super .setTargetDataSources(targetDataSources); //设置默认的数据源 super .setDefaultTargetDataSource(ds1); //调用父类方法,从而初始化最终用于数据源切换的resolvedDataSources super .afterPropertiesSet(); } } |
需要注意的是:重写父类的afterPropertiesSet方法后,我们一定要调用 super.afterPropertiesSet(); 否则无法生成最终用于数据源切换的。这里我们自定义的数据源主要是做两个操作,第一,设置切换的标识符;第二是设备必要的 AbstractRoutingDataSource里面的三大对象即可,然后调用父类的方法进行参数的初始化。
三 代码测试。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | @RestController @RequestMapping ( "user" ) public class UserController { @Autowired UserService userServer; @PostMapping ( "/new" ) public JsonVo<User> addUser() { CommonConstant.ds_LookupKey.set( "w" ); User user= new User().builder() .name(String.valueOf( new Random().nextInt( 1000 ))) .money( new Random().nextInt()) .createTime( new Date()) .build(); userServer.addUser(user); return JsonVo.<User>builder().code( 0 ).data(user).build(); } @PostMapping ( "/list" ) public JsonVo<User> list() { CommonConstant.ds_LookupKey.set( "r" ); List<User> userList= userServer.getList(); return JsonVo.<User>builder().code( 0 ).dataList(userList).build(); } } |
可以看出,我们只是精简和优化了自定义的数据源,对于程序中的硬切换标识符,暂时还是没有办法拿到,后面一篇,我们通过mybatis插件的方式,拿掉这个硬编码的标识符。
说明:
本代码思想逻辑以及配图,均来自对大师视频的学习,通过自己的总结而来,本人并无视频中的提到的课件,以下代码均为自己所写。配图如有侵权,请联系删除。
原学习视频地址: https://www.bilibili.com/video/BV1YT4y1X7v7?p=3&spm_id_from=pageDriver
最后感谢大师无私奉献学习视频,至敬大师的作品。请有学习时间的同学,可以观看原大师的作品。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)