Mybatis中兼容多数据源的databaseId(databaseIdProvider)的简单使用方法

 更新时间:2024年07月08日 08:43:07   作者:Variazioni  
本文主要介绍了Mybatis中兼容多数据源的databaseId(databaseIdProvider)的简单使用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

最近有兼容多数据库的需求,原有数据库使用的mysql,现在需要同时兼容mysql和pgsql,后期可能会兼容更多。

mysql和pgsql很多语法和函数不同,所以有些sql需要写两份,于是在全网搜索如何在mapper中sql不通用的情况下兼容多数据库,中文网络下,能搜到的解决方案大概有两种:1.使用@DS注解的动态数据源;2.使用数据库厂商标识,即databaseIdProvider。第一种多用来同时连接多个数据源,且配置复杂,暂不考虑。第二种明显符合需求,只需要指定sql对应的数据库即可,不指定的即为通用sql。

常规方法

在全网搜索databaseIdProvider的使用方法,大概有两种:

1.在mybatis的xml中配置,大多数人都能搜到这个结果:

<databaseIdProvider type="DB_VENDOR">
  <property name="MySQL" value="mysql"/>
  <property name="Oracle" value="oracle" />
</databaseIdProvider>

然后在mapper中:

<select id="selectStudent" databaseId="mysql">
    select * from student where name = #{name} limit 1
</select>
<select id="selectStudent" databaseId="oracle">
    select * from student where name = #{name} and rownum < 2
</select>

2.创建mybatis的配置类:

import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.apache.ibatis.mapping.VendorDatabaseIdProvider;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;
import java.util.Properties;

@Configuration
public class MyBatisConfig {
  @Bean
  public DatabaseIdProvider databaseIdProvider() {
    VendorDatabaseIdProvider provider = new VendorDatabaseIdProvider();
    Properties props = new Properties();
    props.setProperty("Oracle", "oracle");
    props.setProperty("MySQL", "mysql");
    props.setProperty("PostgreSQL", "postgresql");
    props.setProperty("DB2", "db2");
    props.setProperty("SQL Server", "sqlserver");
    provider.setProperties(props);
    return provider;
  }
  
  @Bean
  public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
    SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
    factoryBean.setDataSource(dataSource);
    factoryBean.setMapperLocations(
        new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*Mapper.xml"));
    factoryBean.setDatabaseIdProvider(databaseIdProvider());
    return factoryBean.getObject();
  }
}

这两种方法,包括在mybatis的github和官方文档的说明,都是看得一头雾水,因为前后无因果关系,DB_VENDOR这种约定好的字段也显得很奇怪,为什么要配置DB_VENDOR?为什么mysql需要写键值对?键值对的key是从那里来的?全网都没有太清晰的说明。

一些发现

有没有更简单的办法?

mybatis的入口是SqlSessionFactory,如果要了解mybatis的运行原理,从这个类入手是最合适的,于是顺藤摸瓜找到了SqlSessionFactoryBuilder类,这个类有很多build方法,打断点之后发现当前配置走的是

  public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }

这个Configuration类就非常显眼了,点进去之后发现这个类的成员变量就是可以在application.yml里直接设置值的变量

public class Configuration {
  protected Environment environment;
  protected boolean safeRowBoundsEnabled;
  protected boolean safeResultHandlerEnabled;
  protected boolean mapUnderscoreToCamelCase;
  protected boolean aggressiveLazyLoading;
  protected boolean multipleResultSetsEnabled;
  protected boolean useGeneratedKeys;
  protected boolean useColumnLabel;
  protected boolean cacheEnabled;
  protected boolean callSettersOnNulls;
  protected boolean useActualParamName;
  protected boolean returnInstanceForEmptyRow;
  protected String logPrefix;
  protected Class<? extends Log> logImpl;
  protected Class<? extends VFS> vfsImpl;
  protected LocalCacheScope localCacheScope;
  protected JdbcType jdbcTypeForNull;
  protected Set<String> lazyLoadTriggerMethods;
  protected Integer defaultStatementTimeout;
  protected Integer defaultFetchSize;
  protected ResultSetType defaultResultSetType;
  protected ExecutorType defaultExecutorType;
  protected AutoMappingBehavior autoMappingBehavior;
  protected AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior;
  protected Properties variables;
  protected ReflectorFactory reflectorFactory;
  protected ObjectFactory objectFactory;
  protected ObjectWrapperFactory objectWrapperFactory;
  protected boolean lazyLoadingEnabled;
  protected ProxyFactory proxyFactory;
  protected String databaseId;
  protected Class<?> configurationFactory;
  protected final MapperRegistry mapperRegistry;
  protected final InterceptorChain interceptorChain;
  protected final TypeHandlerRegistry typeHandlerRegistry;
  protected final TypeAliasRegistry typeAliasRegistry;
  protected final LanguageDriverRegistry languageRegistry;
  protected final Map<String, MappedStatement> mappedStatements;
  protected final Map<String, Cache> caches;
  protected final Map<String, ResultMap> resultMaps;
  protected final Map<String, ParameterMap> parameterMaps;
  protected final Map<String, KeyGenerator> keyGenerators;
  protected final Set<String> loadedResources;
  protected final Map<String, XNode> sqlFragments;
  protected final Collection<XMLStatementBuilder> incompleteStatements;
  protected final Collection<CacheRefResolver> incompleteCacheRefs;
  protected final Collection<ResultMapResolver> incompleteResultMaps;
  protected final Collection<MethodResolver> incompleteMethods;
  protected final Map<String, String> cacheRefMap;
……

这里面的配置有些非常眼熟,比如logImpl,可以使用mybatis.configuration.log-impl直接设置值,那么同理,databaseId是不是也可以使用mybatis.configuration.databaseId设置值?答案是肯定的,而且这样设置值,绕过了databaseIdProvider也可以生效。

最简单的方法

如果你的springboot偏向使用application.yml配置或者使用了spring cloud config,又要兼容多数据库,那么你可以加一条配置

mybatis.configuration.database-id: mysql
或者
mybatis.configuration.database-id: orcale

然后在你的mapper中

<select id="selectStudent" databaseId="mysql">
    select * from student where name = #{name} limit 1
</select>
<select id="selectStudent" databaseId="oracle">
    select * from student where name = #{name} and rownum < 2
</select>
或者
<select id="selectStudent">
    select * from student where 
    <if test="_databaseId=='mysql'">
        name = #{name} limit 1
    </if>
    <if test="_databaseId=='oracle'">
        name = #{name} and rownum < 2
    </if>
</select>

即可切换数据库,不影响其他任何配置,而且也不用纠结databaseIdProvider里的key应该怎么填写了。

到此这篇关于Mybatis中兼容多数据源的databaseId(databaseIdProvider)的简单使用方法的文章就介绍到这了,更多相关Mybatis兼容多数据源内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java实现菜单树的示例代码

    java实现菜单树的示例代码

    这篇文章主要为大家详细介绍了java实现菜单树的相关知识,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-12-12
  • Java调用Python代码实现Word转化为PDF格式

    Java调用Python代码实现Word转化为PDF格式

    这篇文章主要为大家详细介绍了Java如何实现调用Python代码实现Word转化为PDF格式,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2026-03-03
  • SpringBoot轻松实现ip解析(含源码)

    SpringBoot轻松实现ip解析(含源码)

    IP地址一般以数字形式表示,如192.168.0.1,IP解析是将这个数字IP转换为包含地区、城市、运营商等信息的字符串形式,如“广东省深圳市 电信”,这样更方便人理解和使用,本文给大家介绍了SpringBoot如何轻松实现ip解析,需要的朋友可以参考下
    2023-10-10
  • Java接口防抖/幂等性解决方案(redis)

    Java接口防抖/幂等性解决方案(redis)

    在Java项目开发过程中并发处理与幂等性问题紧密相关,这也导致了一些人认为解决幂等性就是解决高并发的问题,这篇文章主要介绍了Java接口防抖/幂等性(redis)的相关资料,需要的朋友可以参考下
    2025-07-07
  • SpringBoot实现动态数据源切换的项目实践

    SpringBoot实现动态数据源切换的项目实践

    在实际开发过程中,我们经常遇到需要同时操作多个数据源的情况,本文主要介绍了SpringBoot实现动态数据源切换的项目实践,具有一定的参考价值,感兴趣的可以了解一下
    2024-04-04
  • IDEA EasyCode 一键帮你生成所需代码

    IDEA EasyCode 一键帮你生成所需代码

    这篇文章主要介绍了IDEA EasyCode 一键帮你生成所需代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • 基于springboot+enum配置化的方法

    基于springboot+enum配置化的方法

    本文主要介绍利用Springboot结合枚举类enum进行自定义参数的初始化和应用,通过@Value注解实现参数的动态注入,以实现灵活可维护的配置管理,具有一定的参考价值,感兴趣的可以了解一下
    2024-09-09
  • 详解RSA加密算法的原理与Java实现

    详解RSA加密算法的原理与Java实现

    这篇文章主要和大家分享非对称加密中的一种算法,那就是 RSA 加密算法。本文介绍了RSA算法的原理与Java实现,感兴趣的小伙伴可以尝试一下
    2022-10-10
  • IntelliJ IDEA中设置数据库连接全局共享的步骤详解

    IntelliJ IDEA中设置数据库连接全局共享的步骤详解

    本文详解IntelliJ IDEA数据库连接全局共享设置,通过创建/选择数据源并设为全局,实现多项目间统一连接,提升效率、减少配置错误,感兴趣的可以了解一下
    2025-07-07
  • springboot集成@DS注解实现数据源切换的方法示例

    springboot集成@DS注解实现数据源切换的方法示例

    本文主要介绍了springboot集成@DS注解实现数据源切换的方法示例,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03

最新评论