0


Springboot 配置动态多数据源(Mybatis-plus)

前言:在项目中需要用到动态切换多数据源,查阅Mybatis-plus文档得知可以通过@DS注解,但该方法主要针对不同内容的数据源,而目前场景是相同内容的数据库需要在运行时根据请求头动态切换,因此文档方法不适用。

注意,不要使用dynamic-datasource-spring-boot-starter依赖包。

一、动态多数据源的场景

  1. 应用不拆,数据库拆
  2. 读写分离

二、动态多数据源的实现

网上文章非常多,大体思路都差不多,笔者在这里不重复放置代码了,例如:《springboot 中动态切换数据源》
不过目前找到的文章方法在项目整合了Mybatis-plus的情况下基本都有问题,以下是这几天遇到的问题和解决方案。

三、问题与解决方案

1. 找不到事务管理器

No qualifying bean of type 'org.springframework.transaction.TransactionManager

可以参照《mybatis-plus多数据源事务报错 》,在Springboot中,每一个事务管理器都需要对应一个datasource,而多数据源操作时,需要在@Transactional注解中指定事务管理器,或者配置默认事务管理器。
不过笔者在《springboot动态切换多个数据源》中发现,可以直接将自定义的dynamicDataSource作为dataSource传给事务管理器,并设置为默认事务管理器,这样就不用配置多个事务管理器了,代码如下:

@Bean(name ="platformTransactionManager")@PrimarypublicPlatformTransactionManagerplatformTransactionManager(){PlatformTransactionManager transactionManager =newDataSourceTransactionManager(dynamicDataSource());return transactionManager;}

2. DataSource没有初始化

DataSource router not initialized

这个问题比较奇特,具体解决方法是在stack overflow中看到的。在自定义的DynamicDataSource类的实现方法中添加如下一行代码:

dataSource.afterPropertiesSet();

该方法目的是让Bean设置好所有属性后再执行初始化操作。

3. 找不到数据源

Invalid bound statement (not found)

这个问题是最坑的,具体原因参照《mybatis升级为mybatis-plus踩到的坑》,而网上很多多数据源文章都没有提到这一点。解决方法也很简单,就是将配置的SqlSessionFactory改为MybatisSqlSessionFactoryBean。

@BeanpublicMybatisSqlSessionFactoryBeanSqlSessionFactory()throwsException{MybatisSqlSessionFactoryBean sqlSessionFactoryBean =newMybatisSqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dynamicDataSource());// dynamicDataSource()为自己定义的实现方法
        sqlSessionFactoryBean.setMapperLocations(newPathMatchingResourcePatternResolver().getResources("classpath*:Mapper/*.xml")// 填写自己的XML路径);return sqlSessionFactoryBean;}

该问题的起源,也是因为导入了Mybatis plus才出现的,导入mybatis-plus-boot-starter依赖包,可以看到有一个MybatisPlusAutoConfiguration类。
在这里插入图片描述
点进去,发现有一个这样的Bean,以及注解

TODO 使用 MybatisSqlSessionFactoryBean 而不是 SqlSessionFactoryBean

,以下都是源码。所以可以知道,在Mybatis plus框架中,使用的都是封装后的MybatisSqlSessionFactoryBean。

@Bean@ConditionalOnMissingBeanpublicSqlSessionFactorysqlSessionFactory(DataSource dataSource)throwsException{// TODO 使用 MybatisSqlSessionFactoryBean 而不是 SqlSessionFactoryBeanMybatisSqlSessionFactoryBean factory =newMybatisSqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setVfs(SpringBootVFS.class);if(StringUtils.hasText(this.properties.getConfigLocation())){
            factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));}applyConfiguration(factory);if(this.properties.getConfigurationProperties()!=null){
            factory.setConfigurationProperties(this.properties.getConfigurationProperties());}if(!ObjectUtils.isEmpty(this.interceptors)){
            factory.setPlugins(this.interceptors);}if(this.databaseIdProvider !=null){
            factory.setDatabaseIdProvider(this.databaseIdProvider);}if(StringUtils.hasLength(this.properties.getTypeAliasesPackage())){
            factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());}if(this.properties.getTypeAliasesSuperType()!=null){
            factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());}if(StringUtils.hasLength(this.properties.getTypeHandlersPackage())){
            factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());}if(!ObjectUtils.isEmpty(this.typeHandlers)){
            factory.setTypeHandlers(this.typeHandlers);}if(!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())){
            factory.setMapperLocations(this.properties.resolveMapperLocations());}// TODO 对源码做了一定的修改(因为源码适配了老旧的mybatis版本,但我们不需要适配)Class<?extendsLanguageDriver> defaultLanguageDriver =this.properties.getDefaultScriptingLanguageDriver();if(!ObjectUtils.isEmpty(this.languageDrivers)){
            factory.setScriptingLanguageDrivers(this.languageDrivers);}Optional.ofNullable(defaultLanguageDriver).ifPresent(factory::setDefaultScriptingLanguageDriver);// TODO 自定义枚举包if(StringUtils.hasLength(this.properties.getTypeEnumsPackage())){
            factory.setTypeEnumsPackage(this.properties.getTypeEnumsPackage());}// TODO 此处必为非 NULLGlobalConfig globalConfig =this.properties.getGlobalConfig();// TODO 注入填充器if(this.applicationContext.getBeanNamesForType(MetaObjectHandler.class,false,false).length >0){MetaObjectHandler metaObjectHandler =this.applicationContext.getBean(MetaObjectHandler.class);
            globalConfig.setMetaObjectHandler(metaObjectHandler);}// TODO 注入主键生成器if(this.applicationContext.getBeanNamesForType(IKeyGenerator.class,false,false).length >0){IKeyGenerator keyGenerator =this.applicationContext.getBean(IKeyGenerator.class);
            globalConfig.getDbConfig().setKeyGenerator(keyGenerator);}// TODO 注入sql注入器if(this.applicationContext.getBeanNamesForType(ISqlInjector.class,false,false).length >0){ISqlInjector iSqlInjector =this.applicationContext.getBean(ISqlInjector.class);
            globalConfig.setSqlInjector(iSqlInjector);}// TODO 设置 GlobalConfig 到 MybatisSqlSessionFactoryBean
        factory.setGlobalConfig(globalConfig);return factory.getObject();}

4. jdbc not connection问题
该问题主要需要检查配置文件,尤其是url要改成jdbc-url,格式如下

spring:datasource:database01:jdbc-url:username:password:driver-class-name:database02:jdbc-url:username:password:driver-class-name:

本文转载自: https://blog.csdn.net/qq_43812006/article/details/131093334
版权归原作者 西宇•利昂 所有, 如有侵权,请联系我们删除。

“Springboot 配置动态多数据源(Mybatis-plus)”的评论:

还没有评论