本文转载自微信公众号《小姐姐的味道》,作者小姐姐养的02号狗。转载本文请联系味觉小姐公众号。在很多情况下,我们确实需要在一个服务中访问多个数据源。虽然它使整体设计不那么优雅,但现实世界确实需要它。例如,您的企业服务于两个比较大的客户,但您希望他们能够共享一组代码。也就是说,你的代码一开始没有考虑多租户的设计,后来却出现了这么蛋疼的需求。但值得庆幸的是,这不是爆炸性的租户增长。除了引入一些分库分表组件外,Spring本身还提供了AbstractRoutingDataSource的方法,使得管理大部分数据源成为可能。其实分库分表组件的使用有很多限制。你得先理清这狗屎山,然后你还要忍受中间件对你SQL的苛刻要求;相反,一些疯狂的方式可以使代码尽可能多地更改。减少。心不如行动。接下来,让我们看看它的具体实现。一、基本原理多个数据源之间动态切换的核心是spring底层提供了AbstractRoutingDataSource类,用于数据源路由。AbstractRoutingDataSource实现了DataSource接口,所以我们可以直接将其注入到DataSource的属性中。我们主要是继承这个类,在里面实现determineCurrentLookupKey()方法,这个方法只需要返回一个数据库的名字即可。比如Controller通过获取前端业务传过来的值来分发业务逻辑。它可以手动设置当前请求的数据库ID,然后路由到正确的数据库表。@ControllerpublicclassARDTestController{@GetMapping("test")publicvoidchifeng(){//db-a应该是上层传下来的属性,我们可以放在ThreadLocalDataSourceContextHolder.setDbKey("db-a");}}那么当sql语句执行时,它是如何知道需要切换到哪个数据源的呢?是不是需要一直传db-a属性?在Java中,可以使用ThreadLocal来绑定这个透明属性。Spring的嵌套事务等实现原理也是基于ThreadLocal的。因此,DataSourceContextHolder。本质上是一个操作ThreadLocal的类。publicclassDataSourceContextHolder{privatestaticInheritableThreadLocaldbKey=newInheritableThreadLocal<>();publicstaticvoidsetDbKey(Stringkey){dbKey.set(key);}publicstaticStringgetDbKey(){returndbKey.get();}}2.配置代码首先我们自定义配置文件的格式。如下代码所示,配置了db-a和db-b两个数据库。multi:dbs:db-a:driver-class-name:org.h2.Driverurl:jdbc:h2:mem:dba;MODE=MYSQL;DATABASE_TO_UPPER=false;db-b:driver-class-name:org.h2。Driverurl:jdbc:h2:mem:dbb;MODE=MYSQL;DATABASE_TO_UPPER=false;然后,我们将其解析为属性。@ConfigurationProperties(prefix="multi")@ConfigurationpublicclassDbsProperties{privateMap>dbs=newHashMap<>();publicMap>getDbs(){returndbs;}publicvoidsetDbs(Map>dbs){this.dbs=dbs;}}下一步是为整个应用程序配置默认数据源。可以看到,它的主要逻辑是在运行时从ThreadLocal中取回预先设定的值。publicclassDynamicDataSourceextendsAbstractRoutingDataSource{@OverrideprotectedObjectdetermineCurrentLookupKey(){returnDataSourceContextHolder.getDbKey();}}最后一步是在整个项目中设置默认的DataSource。注意,我们生成DynamicDataSource后,还需要提供targetDataSource和defaultTargetDataSource的值,它才能正常工作。@ConfigurationpublicclassDynamicDataSourceConfiguration{@AutowiredDbsPropertiesproperties;@BeanpublicDataSourcedataSource(){DynamicDataSourcedataSource=newDynamicDataSource();finalMap