多数据源处理

预备知识-ThreadLocal

ThreadLocal是线程局部变量,所谓的线程局部变量,就是仅仅只能被本线程访问,不能在线程之间进行共享访问的变量。

关键抽象类-AbstractRoutingDataSource

官方注释如下:

  • Abstract {@link javax.sql.DataSource} implementation that routes {@link #getConnection()}
  • calls to one of various target DataSources based on a lookup key. The latter is usually
  • (but not necessarily) determined through some thread-bound transaction context.

大概意思是:
就是getConnection()根据查找lookup key键对不同目标数据源的调用,通常是通过(但不一定)某些线程绑定的事物上下文来实现。

通过这我们知道可以实现:

  • 多数据源的动态切换,在程序运行时,把数据源数据源动态织入到程序中,灵活的进行数据源切换。
  • 基于多数据源的动态切换,我们可以实现读写分离,这么做缺点也很明显,无法动态的增加数据源。

逻辑思路

  • DynamicDataSource继承AbstractRoutingDataSource类,并实现了determineCurrentLookupKey()方法。
  • 我们配置的多个数据源会放在AbstractRoutingDataSource的 targetDataSources和defaultTargetDataSource中,然后通过afterPropertiesSet()方法将数据源分别进行复制到resolvedDataSources和resolvedDefaultDataSource中。
  • AbstractRoutingDataSource的getConnection()的方法的时候,先调用determineTargetDataSource()方法返回DataSource在进行getConnection()。

实现多数据源

  1. 步骤1,在spring boot中,增加多数据源的配置
  2. 步骤2,扩展Spring的AbstractRoutingDataSource抽象类,
    AbstractRoutingDataSource中的抽象方法determineCurrentLookupKey是实现多数据
    源的核心,并对该方法进行Override
  3. 步骤3,配置DataSource,指定数据源的信息
  4. 步骤4,通过注解,实现多数据源
  5. 步骤5、配置加上(exclude={DataSourceAutoConfiguration.class})
    多数据源处理

关于事务

只支持单库事务,也就是说切换数据源要在开启事务之前执行。 spring DataSourceTransactionManager进行事务管理,开启事务,会将数据源缓存到DataSourceTransactionObject对象中进行后续的commit rollback等事务操作。
多数据源处理
多数据源处理

使用经验

出现多数据源动态切换失败的原因是因为在事务开启后,数据源就不能再进行随意切换了,也就是说,一个事务对应一个数据源。那么传统的Spring管理事务是放在Service业务层操作的,所以更换数据源的操作要放在这个操作之前进行。也就是切换数据源操作放在Controller层,可是这样操作会造成Controller层代码混乱的结果。故而想到的解决方案是将事务管理在数据持久 (Dao层) 开启,切换数据源的操作放在业务层进行操作,就可在事务开启之前顺利进行数据源切换,不会再出现切换失败了。