springboot使用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 {@Beanpublic 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;}@Beanpublic 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应该怎么填写了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/828892.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode //C - 38. Count and Say Medium Topics Companies

38. Count and Say The count-and-say sequence is a sequence of digit strings defined by the recursive formula: countAndSay(1) “1”countAndSay(n) is the way you would “say” the digit string from countAndSay(n-1), which is then converted into a differen…

前端开发禁用F12和右键检查元素处理

只需要对应的页面引入西面这个js文件就行(创建一个.js文件,将下面代码粘贴进去页面引用后使用) window.onload function () {document.onkeydown function () {var e window.event || arguments[0];//屏蔽F12if (e.keyCode 123) {return false;//屏蔽CtrlShiftI} else if …

【ARMv9 DSU-120 系列 10 -- PMU 详细介绍】

请阅读【Arm DynamIQ™ Shared Unit-120 专栏 】 文章目录 DSU-120 PMUPMU features事件接口系统寄存器计数器PMU寄存器接口PMU eventsPMU interruptExternal cluster PMU registersDSU-120 PMU DynamIQ™共享单元-120(DSU-120)包括性能监视器,这些监视器使您能够在运行时收…

Laravel 6 - 第十七章 配置数据库

​ 文章目录 Laravel 6 - 第一章 简介 Laravel 6 - 第二章 项目搭建 Laravel 6 - 第三章 文件夹结构 Laravel 6 - 第四章 生命周期 Laravel 6 - 第五章 控制反转和依赖注入 Laravel 6 - 第六章 服务容器 Laravel 6 - 第七章 服务提供者 Laravel 6 - 第八章 门面 Laravel 6 - …

《动手学深度学习(Pytorch版)》Task01:初识深度学习——4.22打卡

《动手学深度学习&#xff08;Pytorch版&#xff09;》Task01&#xff1a;初识深度学习 深度学习介绍AI地图深度学习任务图片分类物体检测和分割样式迁移人脸合成文字生成图片文字生成无人驾驶 案例&#xff1a;广告点击完整过程 QAQ&#xff1a;机器学习的可解释性&#xff1a…

electron使用typescript

引入 TypeScript 到 Electron 项目中是一个增强代码质量和开发体验的好方法&#xff0c;因为 TypeScript 提供了静态类型检查、接口和类等强大的语言特性。下面是将 TypeScript 集成到 Electron 项目中的步骤&#xff1a; 1. 初始化项目 如果你还没有创建 Electron 项目&…

【C++ STL序列容器】list 双向链表

文章目录 【 1. 基本原理 】【 2. list 的创建 】2.1 创建1个空的 list2.2 创建一个包含 n 个元素的 list&#xff08;默认值&#xff09;2.3 创建一个包含 n 个元素的 list&#xff08;赋初值&#xff09;2.4 通过1个 list 初始化另一个 list2.5 拷贝其他类型容器的指定元素创…

速盾:ddos高防ip原理

DDoS&#xff08;分布式拒绝服务攻击&#xff09;是一种常见的网络攻击方式&#xff0c;通过向目标服务器发送大量的请求&#xff0c;使其无法正常处理合法用户的请求&#xff0c;从而导致服务不可用。为了应对这种攻击&#xff0c;高防IP技术应运而生。 高防IP是一种专门为抵…

oracle--merge into :匹配则更新不匹配则插入

merge into &#xff1a;匹配则更新不匹配则插入 --语法 merge into 目标表 using &#xff08;增量&#xff09; on (匹配字段&#xff09; where matched then update set --update和sel直接不需要加表名 when not matched then insert values--insert和values之间不需要加i…

swagger文档接口根据包分组配置

文章目录 一、引言二、配置2.1 原本配置及效果2.2 更改后配置及效果 三、结束 一、引言 关于接口文档的详细配置可参见文章API文档生成工具-----Knife4j的详细介绍、配置及应用 此文章是基于已经完成基础配置的前提下,如何根据不同包进行分组 二、配置 2.1 原本配置及效果 …

Hadoop实战——MapReduce-字符统计(超详细教学,算法分析)

目录 一、前提准备工作 启动hadoop集群 二、实验过程 1.虚拟机安装先设置端口转发 2.上传对应文件 3.编写Java应用程序 4. 编译打包程序 5. 运行程序 三、算法设计和分析 算法设计 算法分析 四、实验总结 实验目的&#xff1a;给定一份英文文本&#xff0c;统计每个…

matlab新手快速上手5(蚁群算法)

本文根据一个较为简单的蚁群算法框架详细分析蚁群算法的实现过程&#xff0c;对matlab新手友好&#xff0c;源码在文末给出。 蚁群算法简介&#xff1a; 蚁群算法是一种启发式优化算法&#xff0c;灵感来源于观察蚂蚁寻找食物的行为。在这个算法中&#xff0c;解决方案被看作是…

数学分析复习:中值定理、反函数定理

文章目录 中值定理、反函数定理 本篇文章适合个人复习翻阅&#xff0c;不建议新手入门使用 中值定理、反函数定理 定理&#xff1a;Rolle&#xff08;罗尔&#xff09;中值定理 设实值函数 f ∈ C 0 [ a , b ] f\in C^0[a,b] f∈C0[a,b] 且在 ( a , b ) (a,b) (a,b) 上可微&…

平衡二叉树、红黑树、B树、B+树

Tree 1、前言2、平衡二叉树和红黑树3、B树和B树3.1、B树的构建3.2、B树和B树的区别3.3、数据的存储方式 1、前言 本文侧重在理论方面对平衡二叉树、红黑树、B树和B树的各方面性能进行比较。不涉及编程方面的实现。而关于于平衡二叉树在C中的实现&#xff0c;我的上一篇文章平衡…

Golang实现一个批量自动化执行树莓派指令的软件(4)上传

简介 话接上篇 Golang实现一个批量自动化执行树莓派指令的软件(3)下载 &#xff0c; 继续实现上传 环境描述 运行环境: Windows&#xff0c; 基于Golang&#xff0c; 暂时没有使用什么不可跨平台接口&#xff0c; 理论上支持Linux/MacOS 目标终端&#xff1a;树莓派DebianOS(主…

【JS】前端文件读取FileReader操作总结

前言&#xff1a;开发中经常遇到文件上传的场景&#xff0c;有时需要前端将文件内容读取出来再以base64格式传到接口。 目录 FileReader主要方法readAsArrayBuffer(blob)readAsText(blob, [encoding])readAsDataURL(blob) 主要事件React antd Upload 组件示例 FileReader Fil…

Vue Router基础知识整理

Vue Router基础知识整理 1. 安装与使用&#xff08;Vue3&#xff09;安装使用 2. 配置路径别名和VSCode路径提示&#xff08;了解&#xff09;3. 使用查询字符串或路径传参query动态路由 与 params 4. router-link、定义别名、定义路由名称、编程式导航定义别名 aliasrouter-li…

李沐66_使用注意力机制的seq2seq——自学笔记

加入注意力 1.编码器对每次词的输出作为key和value 2.解码器RNN对上一个词的输出是query 3.注意力的输出和下一个词的词嵌入合并进入RNN 一个带有Bahdanau注意力的循环神经网络编码器-解码器模型 总结 1.seq2seq通过隐状态在编码器和解码器中传递信息 2.注意力机制可以根…

ELK技术介绍:背景、功能及应用场景全面解析

一、ELK概述 ELK是由Elasticsearch、Logstash和Kibana三个开源软件组成的日志管理解决方案&#xff0c;这一组合在近年来得到了广泛的关注和应用。ELK的出现&#xff0c;源于大数据和云计算技术的快速发展&#xff0c;以及对高效日志管理的迫切需求。 随着企业信息化程度…

【10-10-10旁观思维】项目管理必会的思维分析工具 08(送模板~)

&#x1f468;‍&#x1f4bb;&#x1f469;‍&#x1f4bb;面对一个决策或选择&#xff0c;当你犹豫不决时&#xff0c;可以想一下 ⏰10分钟后&#xff0c;自己是怎么看待自己现在的决策&#xff0c;依然保持一致亦或会后悔&#xff1b; ⏰10个月后&#xff0c;你又会如何思…