背景:
公司有多套环境,每个环境执行数据库脚本的时机也不一样,久而久之,不同环境相同表的结构就有了差异,需要做一个工具进行对比。
分析:
同一套环境下有很多数据库,不同环境的数据库连接肯定也是不一样的,那么如何做到查询指定环境下的某一个数据库,需要动态的去切换数据源,根据当前的查询条件路由对应的数据库。可以使用AOP在执行SQL前切换数据源。
实现逻辑:
- 用 AbstractRoutingDataSource 实现动态切换数据源,向容器中注册自定义的 AbstractRoutingDataSource 实现类(AbstractRoutingDataSource的相关介绍,我这篇文章有介绍,点我)。
- 用 ThreadLocal 线程级别变量存放当前数据源key。
- 利用 AOP 在执行SQL时切换数据源。
我这里因为公司使用的是阿里的DRDS,数据库是按照用户名进行隔离的,一个用户名对应一个数据库,所以多套环境下数据库的url连接都是一样的,只是连接的账号密码不一样,所以只需要把账号和密码配置在 application.xml 中。
spring:
datasource:
default:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://xxxxxxx/xxx?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true
username: xxx
password: xxx
databaselist:
- database: dev_xx1
username: dev_xx1
password: dev_123
- database: dev_xx2
username: dev_xx2
password: dev_123
- database: test_xx1
username: test_xx1
password: test_123
- database: test_xx2
username: test_xx2
password: test_123
mybatis:
mapper-locations: classpath:/mapper/*.xml
DataSourceContextHolder
/**
* 数据源上下文
*/
@Slf4j
@UtilityClass
public class DataSourceContextHolder {
/**
* 线程级别的私有变量
*/
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
public String getDataSourceName() {
return CONTEXT_HOLDER.get();
}
public void setDataSourceName(String name) {
log.info("切换到:{}数据源", name);
CONTEXT_HOLDER