跳至主要內容

多数据源

chanchaw大约 2 分钟languagejava

概述

业务代码通过 spring 调用持久层框架(mybatis)读写数据库时会获取与数据库的 connection,项目中自制多个数据源分别连接不同的数据库,在获取 connection 动态返回需要的连接即可。要求制作自定义的实现 DataSource 接口的类,并注解为 primary 数据源,该数据源中动态返回多个数据源中的一个。

实现

静态分包方式

自定义多套数据源关联到 xml 到 dao 类,参考仓库:https://gitee.com/chanchaw/static_package_mult_dsopen in new window

  1. xml 文件在 resources/mappers/order、resources/mappers/user 分两部分

  2. dao 类在 com.ccsoft.dao.order、com.ccsoft.dao.user 分两部分

  3. 根据 yml 配置文件制作多个数据源 OrderMybatisConfig、UserMybatisConfig

在后续的业务逻辑中当做单数据源一样编写代码

继承 AbstractRoutingDataSource

spring 本身支持多数据源,并且支持动态切换。该套逻辑中 spring 维护了一个全数据源 Map 对象 targetDataSources 以及一个默认数据源对象 defaultDataSource,通过自定义方法返回“全数据源”的 key 则 spring 会自动切换为对应的数据源执行访问数据库的方法。所以自定义实现 AbstractRoutingDataSource 的类中重写两个方法:afterPropertiesSet、determineCurrentLookupKey 即可。本方案见仓库:https://gitee.com/chanchaw/multdsopen in new window

  1. 重写 afterPropertiesSet 构建全数据源 targetDataSources 以及默认数据源 defaultDataSource,最后还要调用父类方法 afterPropertiesSet。
  2. 重写 determineCurrentLookupKey 返回线程安全的当前需要的数据源的 flag 即可。

实现动态切换

不做动态切换的话,在每个业务方法执行之前都要手动指定当前想要使用的数据源,否则可能被执行到其他无关的数据源上。本案例中手动切换数据源的方法是:DynamicDataSource.multDSSwitcher.set(MultDSSwitcher.READ); 实现自动动态切换数据源有两种方式,分别适用于不同使用场景。

  1. 使用 mybatis 插件的方法,本方法可以判断 sql 是查询还是增删改方法,所以适用于读写分离环境中,对读和写的切换
  2. 使用 aop + 自定义注解的方法适合用于一个大项目被拆分为多个业务数据库的情况,每个数据库实现部分业务,这样执行不同业务时需要切换到对应的数据源上。

问题

在事务中切换数据源会失败,有两种解决方法:

  1. 需要切换数据源的方法使用多线程异步执行,注意使用 throws Exception 将异步线程的错误抛出来
  2. 使用注解 @Transactional(propagation = Propagation.NOT_SUPPORTED) 将切换数据源的方法从事务中独立出来

解决该问题的案例在招商织染的 account.util.AutoWeighingUtils # insert 方法中