mybatis-plus 、 druid 、跨不同数据源、同一个连接跨库查询
项目场景描述1.项目数据库db_data_link和dolphinscheduler数据库db_ds使用同一个mysql实例,分不同的库,为了降低复杂度,给db_data_link的用户赋予了db_ds数据库的只读权限,可以跨库查询
2.项目中还会用到其他的数据库,如hive的meta数据库,也想使用mybatis的快捷查询功能
3.项目中主库只有一个,涉及到事务,其他的都不需要
多种方式调研| 方案 | 核心思路描述 | 总结 | |
|---|---|---|---|
| 方案1 | baomidou官方提供的dynamic-datasource-spring-boot-starter ,功能强大,可以满足各类场景需求,官方帮助文档 | 1.核心原理是做数据源动态切换,mybatis-plus的配置只有一个,在执行时根据注解@ds 来实现切换 | 缺点: 1.在使用的时候仍然需要在具体的mapper或者service加上注解来区分数据源 2.有遇到过多数据源事务提交不满足预期的问题 |
| 方案2 | 配置多数据源、多sqlSessionFactory、多事务 | 多数据源完全隔离,使用各自的sqlSessionFactory | 缺点: 1.多事务时必须要指定事务,但是也可只配置一个事务 2.配置多个数据源时会跟很多的AutoConfiguration冲突:DataSourceAutoConfiguration.class, MybatisPlusAutoConfiguration.class, 3.mybatis-plus默认配置不生效了,有点不能接受 |
| 方案3 | 方案2的升级版本 | 将方案2的缺点想办法跳过 1.很多数据源相关的AutoConfiguration都是数据源相关的,只有一个数据源的时候才会生效,多数据源时只让默认数据源注入spring的bean容器 2.非主数据源在配置sqlSessionFactory时创建,不走spring容器 3.非主数据源不配置事务,这样事务只有一个,使用时就不需要手动指定事务了 | 优点: 不改变已有的任何使用姿势,很丝滑! 1.数据源配置和mybatis-plus都走spring的默认配置 2.事务使用也不用改 |
1.mybatis-plus 支持默认全局参数替换,sql中的库名可以设置成动态参数
variables: dsDb:dolphinscheduler200 # 配置ds的数据库名称
2.domain类表名称无法动态解析,需要使用mybatis-plus的sqlInject插件
@TableName("${dsDb}.t_ds_task_definition_log")
@Bean
public MybatisPlusInterceptor tableNameInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
dynamicTableNameInnerInterceptor.setTableNameHandler((sql, tableName) -> {
return TableNameUtils.evaluateTableName(tableName);
});
interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
// 3.4.3.2 作废该方式
// dynamicTableNameInnerInterceptor.setTableNameHandlerMap(map);
return interceptor;
}
public class TableNameUtils {
@Value("${mybatis-plus.configuration.variables:}")
private Properties variables;
public static TableNameUtils getInstance() {
return ApplicationContextHolder.getInstance(TableNameUtils.class);
}
public static String evaluateTableName(String tableName1) {
String parse = new GenericTokenParser("${", "}", id -> {
Object o = TableNameUtils.getInstance().variables.get(id);
return o.toString();
}).parse(tableName1);
return parse;
}
}
核心配置流程,简单到不敢相信!
@Configuration
@MapperScan(basePackages = "com.redstarclouds.datalink.common.hive.meta.mapper", sqlSessionFactoryRef = "hivemetaSqlSessionFactory")
public class HivemetaDataSourceContext {
@Bean(name = "hivemetaSqlSessionFactory")
public SqlSessionFactory sqlSessionFactory() throws Exception {
HiveConfig hiveConfig = ApplicationContextHolder.getInstance(HiveConfig.class);
HikariDataSource ds = new HikariDataSource();
ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
ds.setUsername(hiveConfig.hivemetadataUser);
ds.setPassword(hiveConfig.hivemetadataPassWord);
ds.setJdbcUrl(hiveConfig.hivemetadataJdbcUrl);
MybatisSqlSessionFactoryBean sessionFactoryBean = new MybatisSqlSessionFactoryBean();
sessionFactoryBean.setDataSource(ds);
sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/hive/*.xml"));
return sessionFactoryBean.getObject();
}
}
注意:
1.扫描包是需要需要指定sqlSessionFactoryRef = "hivemetaSqlSessionFactory"
2.xml文件路径需要和默认的确认开,统一个路径好像只能被一个SqlSessionFactory加载,不是很确定,但是这么做就对了


