文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Mybatis-Plus入门系列(20) -兼容多种数据库

2023-08-23 21:12

关注

有道无术,术尚可求,有术无道,止于术。

前言

在我们实际开发软件产品过程中,数据库的类型可能不是确定的,也有客户会有要求必须用什么数据库,比如很多政府机构要求必须使用国产数据库,所以我们在开发时,需要适配多种数据库。

MySQLOraclePostgreSQL、达梦等数据库在进行增删改查时,都是基于美国国家标准局制定的SQL标准,比如SQL-92SQL-99

但是每个数据库厂商实际的SQL会有较小差异,也就是数据库方言,大家最熟知的就是MySQL分页使用limitOracle分页使用rownum

MyBatis-Plus支持各种标准 SQL 的数据库,接下来我们实际演示如何使用MyBatis-Plus适配各种数据库。
在这里插入图片描述

方案分析

1. 分页

很多数据库分页SQL使用方式都不大相同,MyBatis-Plus内置分页插件PaginationInnerInterceptor已支持多种数据库,官网说明:
在这里插入图片描述

在使用内置分页插件时,可以设置数据库的类型:

@Configuration@MapperScan("com.pearl.pay.mapper") //持久层扫描@EnableTransactionManagement //启用事务管理public class MybatisPlusConfig {    @Bean    @ConditionalOnMissingBean(MybatisPlusInterceptor.class)    public MybatisPlusInterceptor mybatisPlusInterceptor() {        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();        paginationInnerInterceptor.setDbType(DbType.MYSQL);        interceptor.addInnerInterceptor(paginationInnerInterceptor);        return interceptor;    }}

内置分页插件在执行SQL时,会根据当前数据库类型获取分页方言
在这里插入图片描述
分页方言工厂类DialectFactory中,可以看到具体获取方言逻辑,mysqlmariadbclickhouseoceanbase等数据库都是使用mysql方言。
在这里插入图片描述
oracle达梦数据库用的是oracle方言:
在这里插入图片描述
MYSQL 数据库分页语句使用LIMIT组装:
在这里插入图片描述
ORACLE 数据库分页语句使用ROWNUM、ROW_ID组装:
在这里插入图片描述
综上: 在分页时,适配多种数据库只需要在分页插件中设置数据库类型即可。

2. XML自定义SQL

调用MPAPI进行增删改查时,比如调用xxMpper.selectList()时,因为MP在构建SQL时,都是使用的基础标准,所以一般不存在兼容问题。但是我们自己在XML文件中编写SQL,就需要注意各种数据库匹配兼容问题了。

Mybatis本身已经做了多数据库支持,只需要告诉框架用的是什么数据库,可以根据不同的数据库厂商执行不同的语句。

Mybatis中的DatabaseIdProvider (数据库厂商标识提供者)接口声明了获取厂商标识的方法,标识可用于以后为每种数据库类型构建不同的查询,该机制支持多个厂商或版本。

public interface DatabaseIdProvider {  default void setProperties(Properties p) {    // NOP  }  // 根据数据源获取数据库厂商标识  String getDatabaseId(DataSource dataSource) throws SQLException;}

Mybatis也提供了VendorDatabaseIdProvider实现类:

public class VendorDatabaseIdProvider implements DatabaseIdProvider {    // 支持的数据库厂商(需要自己定义),比如: Oracle=》oracle  private Properties properties;  // 获取数据库厂商标识ID(databaseId),eg:oracle  @Override  public String getDatabaseId(DataSource dataSource) {    if (dataSource == null) {      throw new NullPointerException("dataSource cannot be null");    }    try {      return getDatabaseName(dataSource);    } catch (Exception e) {      LogHolder.log.error("Could not get a databaseId from dataSource", e);    }    return null;  }  @Override  public void setProperties(Properties p) {    this.properties = p;  }  // 根据产品名称,获取对应的databaseId。  private String getDatabaseName(DataSource dataSource) throws SQLException {    String productName = getDatabaseProductName(dataSource);    if (this.properties != null) {      for (Map.Entry<Object, Object> property : properties.entrySet()) {        if (productName.contains((String) property.getKey())) {          return (String) property.getValue();        }      }      // no match, return null      return null;    }    return productName;  }  // 从数据源中获取数据库产品名称,比如: Oracle  private String getDatabaseProductName(DataSource dataSource) throws SQLException {    try (Connection con = dataSource.getConnection()) {      DatabaseMetaData metaData = con.getMetaData();      return metaData.getDatabaseProductName();    }  }}

MybatisXML中编写SQL时,有个databaseId属性,可以指定当前语句块属于哪个数据库类型,比如:

<mapper namespace="org.pearl.mybatis.demo.dao.UserMapper">    <select id="selectOneById" resultType="org.pearl.mybatis.demo.pojo.entity.User" databaseId="mysql">    select * from user where user_id = #{id}  select>mapper>

综上:我们只需要配置DatabaseIdProvider 中支持哪些数据库,然后在XML中针对每种数据库方言编写查询语句,并添加databaseId属性,Mybatis会在启动时获取数据源使用的哪个类型数据库,然后执行配置了当前数据库对应的语句

案例演示

1. 配置

搭建工程,集成MPOracleMysql很简单,这里就不赘述了。

在配置文件中,添加对应的OracleMysql连接地址:

spring:  datasource:    type: com.zaxxer.hikari.HikariDataSource    driver-class-name: oracle.jdbc.OracleDriver    url: jdbc:oracle:thin:@127.0.0.1:1521:ORCL    username: root    password: root    #driver-class-name: com.mysql.cj.jdbc.Driver    #url: jdbc:mysql://127.0.0.1:3306/d_account?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai    #username: root    #password: root

MP中添加配置类:

@Configuration@MapperScan("com.pearl.pay.mapper") //持久层扫描@EnableTransactionManagement //启用事务管理public class MybatisPlusConfig {     @Bean    public MybatisPlusInterceptor mybatisPlusInterceptor(DataSource dataSource,DatabaseIdProvider databaseIdProvider) throws SQLException {        // MP插件        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();        // 获取当前数据源对应的数据库类型,添加分页插件        String databaseId = databaseIdProvider.getDatabaseId(dataSource);        DbType dbType = DbType.getDbType(databaseId);        paginationInnerInterceptor.setDbType(dbType);        interceptor.addInnerInterceptor(paginationInnerInterceptor);        return interceptor;    }    @Bean    public DatabaseIdProvider databaseIdProvider() {        // 数据库厂商提供者        DatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider();        Properties p = new Properties();        p.setProperty("Oracle", "oracle");        p.setProperty("Mysql", "mysql");        databaseIdProvider.setProperties(p);        return databaseIdProvider;    }}

2. 简单分页查询

因为MyBatis-Plus内置分页插件已经做了适配,简单的(没有数据库方言)分页查询不用自己写代码适配。

首先添加一个分页查询:

    IPage<User> test(Page<User> page);    
    <select id="test" resultType="com.pearl.entity.User">        select * from user    select>

数据源配置的是Oracle,没有配置databaseId,测试SQL语句打印如下:

SELECT * FROM ( SELECT TMP.*, ROWNUM ROW_ID FROM ( select * from user) TMP WHERE ROWNUM <=10) WHERE ROW_ID > 0

数据源配置为Mysql,测试SQL语句打印如下:

select * from user LIMIT 10

3. 带方言的分页查询

需求查询时间节点小于当前时间的数据。

Oracle当前时间使用的是sysdate函数,Mysql使用的是now()函数,这个时候就需要手动去兼容了。

编写两个重名的查询语句,针对不同的数据库厂商编写SQL,并配置对应的databaseId

    <select id="test" resultType="com.pearl.entity.User" databaseId="mysql">        select * from user t     select>        <select id="test" resultType="com.pearl.entity.User" databaseId="oracle">        select * from user t      select>

也可以使用if语句,判断当前数据库类型,添加不同语句(推荐)。

    <select id="test" resultType="com.pearl.entity.User">        select * from user t        <where>            <if test="_databaseId == 'mysql'">                            if>            <if test="_databaseId == 'oracle'">                            if>        where>    select>

切换数据库,执行如下:

select * from user t where t.create_time <= now() LIMIT 10SELECT * FROM ( SELECT TMP.*, ROWNUM ROW_ID FROM ( select * from user t where t.create_time <= sysdate ) TMP WHERE ROWNUM <=10) WHERE ROW_ID > 0

参考

接下来我们简单了解下OracleMysql的一些区别,便于开发。

数据类型对照:

数据库对比项类型
MySQL数据类型INTEGER、SMALLINT、TINYINT、MEDIUMINT、BIGINT
Oracle数据类型number
MySQL日期和时间date、timestamp、timestamp
Oracle日期和时间date、timestamp
MySQL字符类型char、varchar
Oracle字符类型char、varchar、varchar2、nvarchar、nvarchar2
MySQL大字段LONGTEXT
Oracle大字段clob

常用函数对照:

数据库对比项函数
MySQL获取字符串长度char_length(str)
Oracle获取字符串长度length(str)
MySQL生成随机序列UUID()
Oracle生成随机序列sys_guid()
MySQL时间转换为字符串date_format(NOW(),‘%Y-%m-%d’)
Oracle时间转换为字符串to_char(sysdate, ‘YYYY-MM-DD’)
MySQL字符串型时间转换为时间str_to_date(‘2019-01-01’,‘%Y-%m-%d’)
Oracle字符串型时间转换为时间to_date(‘2019-01-01’, ‘YYYY-MM-DD’)
MySQL包含时分秒的函数转换date_format(NOW(),‘%Y-%m-%d %H:%i:%s’)
Oracle包含时分秒的函数转换str_to_date(‘2019-01-01’,‘%Y-%m-%d %H:%i:%s’)
MySQL当前时间now()
Oracle当前时间sysdate

其他:

数据库对比项支持
MySQL引号双引号和单引号
Oracle引号只能识别单引号
MySQL字符串连接符concat()函数
Oracle字符串连接符可用双竖线连接字符串
MySQL分页limit
Oracle分页rownum

来源地址:https://blog.csdn.net/qq_43437874/article/details/129161055

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-数据库
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯