添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Skip to content

灵活的 QueryWrapper

增删改 查询和分页 章节中,我们随时能看到 QueryWrapper 的身影,QueryWrapper 是用于构造 Sql 的 强有力工具,也是 MyBatis-Flex 的亮点和特色。

提示

QueryWrapper 可以被序列化通过 RPC 进行传输,因此,在微服务项目中,我们可以在客户端(网关、Controller 层等)构造出 QueryWrapper,传给 Provider 层进行查询返回数据。

QueryWrapper 的使用

以下代码是一个完整 Spring Controller 的示例:

在以上的示例中,其核心代码如下所示:

以上代码执行的 Sql 如下:

问题:以上示例中, ACCOUNT.ID.ge(100) 中的 ACCOUNT 是怎么来的?

MyBatis-Flex 使用了 APT 技术,这个 ACCOUNT 是自动生成的。 参考:《 MyBatis-Flex APT 配置 》章节。

select *

其查询生成的 Sql 如下:

select ... as

其查询生成的 Sql 如下:

select 多张表

其查询生成的 Sql 如下:

select function(SQL 函数)

所有函数均在 QueryMethods 类中,以下示例皆为静态导入方法,省略了类名。

示例 :

其查询生成的 Sql 如下:

在使用函数时,一些数字、字符串常量需要通过特定的方法去构造,例如:

  • number():构建数字常量
  • string():构建字符串常量
  • column():构建自定义列

示例:

目前,MyBatis-Flex 已支持 110+ 个常见的 SQL 函数,查看已支持的 所有函数 。 若还不满足,您可以参考 QueryMethods ,然后在自己的项目里进行自定义扩展。

支持的函数 函数说明
count 查询数据总量
distinct 对指定列进行去重
sum 返回指定字段值的和
avg 返回指定列的平均值
min 返回指定列的最小值
max 返回指定列的最大值
abs 返回绝对值
ceil 返回大于或等于 x 的最小整数(向上取整)
ceiling 返回大于或等于 x 的最小整数(向上取整)
floor 返回小于或等于 x 的最大整数(向下取整)
rand 返回 0~1 的随机数
sign 返回 x 的符号,x 是负数、0、正数分别返回 -1、0、1
pi 返回圆周率
truncate 返回数值 x 保留到小数点后 y 位的值
round 返回离 x 最近的整数(四舍五入)
pow 返回 x 的 y 次方
power 返回 x 的 y 次方
sqrt 返回 x 的平方根
exp 返回 e 的 x 次方
mod 返回 x 除以 y 以后的余数
log 返回自然对数(以 e 为底的对数)
log10 返回以 10 为底的对数
radians 将角度转换为弧度
degrees 将弧度转换为角度
sin 求正弦值
asin 求反正弦值
cos 求余弦值
acos 求反余弦值
tan 求正切值
atan 求反正切值
cot 求余切值
charLength 返回字符串 s 的字符数
length 返回字符串 s 的长度
concat 将字符串 s1,s2 等多个字符串合并为一个字符串
concatWs 同 CONCAT(s1, s2, ...),但是每个字符串之间要加上 x
insert 将字符串 s2 替换 s1 的 x 位置开始长度为 len 的字符串
upper 将字符串 s 的所有字符都变成大写字母
lower 将字符串 s 的所有字符都变成小写字母
left 返回字符串 s 的前 n 个字符
right 返回字符串 s 的后 n 个字符
lpad 字符串 s2 来填充 s1 的开始处,使字符串长度达到 len
rpad 字符串 s2 来填充 s1 的结尾处,使字符串长度达到 len
trim 去掉字符串 s 开始处和结尾处的空格
ltrim 去掉字符串 s 开始处的空格
rtrim 去掉字符串 s 结尾处的空格
repeat 将字符串 s 重复 n 次
space 返回 n 个空格
replace 用字符串 s2 代替字符串 s 中的字符串 s1
strcmp 比较字符串 s1 和 s2
substring 获取从字符串 s 中的第 n 个位置开始长度为 len 的字符串
instr 从字符串 s 中获取 s1 的开始位置
reverse 将字符串 s 的顺序反过来
elt 返回第 n 个字符串
field 返回第一个与字符串 s 匹配的字符串的位置
findInSet 返回在字符串 s2 中与 s1 匹配的字符串的位置
curDate 返回当前日期
currentDate 返回当前日期
curTime 返回当前时间
currentTime 返回当前时间
now 返回当前日期和时间
currentTimestamp 返回当前日期和时间
localTime 返回当前日期和时间
sysDate 返回当前日期和时间
localTimestamp 返回当前日期和时间
unixTimestamp 以 UNIX 时间戳的形式返回当前时间
fromUnixTime 把 UNIX 时间戳的时间转换为普通格式的时间
utcDate 返回 UTC(国际协调时间)日期
utcTime 返回 UTC 时间
month 返回日期 d 中的月份值,范围是 1~12
monthName 返回日期 d 中的月份名称,如 january
dayName 返回日期 d 是星期几,如 Monday
dayOfWeek 返回日期 d 是星期几,1 表示星期日,2 表示星期二
weekday 返回日期 d 是星期几,0 表示星期一,1 表示星期二
week 计算日期 d 是本年的第几个星期,范围是 0-53
weekOfYear 计算日期 d 是本年的第几个星期,范围是 1-53
dayOfYear 计算日期 d 是本年的第几天
dayOfMonth 计算日期 d 是本月的第几天
year 返回日期 d 中的年份值
day 返回日期 d 中的天数值
quarter 返回日期 d 是第几季度,范围 1-4
hour 返回时间 t 中的小时值
minute 返回时间 t 中的分钟值
second 返回时间 t 中的秒钟值
timeToSec 将时间 t 转换为秒
secToTime 将以秒为单位的时间 s 转换为时分秒的格式
toDays 计算日期 d 到 0000 年 1 月 1 日的天数
fromDays 计算从 0000 年 1 月 1 日开始 n 天后的日期
dateDiff 计算日期 d1 到 d2 之间相隔的天数
addDate 计算开始日期 d 加上 n 天的日期
subDate 计算起始日期 d 减去 n 天的日期
addTime 计算起始时间 t 加上 n 秒的时间
subTime 计算起始时间 t 加上 n 秒的时间
dateFormat 按照表达式 f 的要求显示日期 d
timeFormat 按照表达式 f 的要求显示时间 t
getFormat 根据字符串 s 获取 type 类型数据的显示格式
version 返回数据库的版本号
connectionId 返回服务器的连接数
database 返回当前数据库名
schema 返回当前数据库 schema
user 返回当前用户的名称
charset 返回字符串 str 的字符集
collation 返回字符串 str 的字符排列方式
lastInsertId 返回最后生成的 auto_increment 值
password 对字符串 str 进行加密
md5 对字符串 str 进行 md5 加密
encode 使用字符串 pswd_str 来加密字符串 str,加密结果是一个二进制数,必须使用 BLOB 类型来保持它
decode 解密函数,使用字符串 pswd_str 来为 crypt_str 解密
format 格式化函数,可以将数字 x 进行格式化,将 x 保留到小数点后 n 位,这个过程需要进行四舍五入
ascii 返回字符串 s 的第一个字符的 ASSCII 码
bin 返回 x 的二进制编码
hex 返回 x 的十六进制编码
oct 返回 x 的八进制编
conv 将 x 从 f1 进制数变成 f2 进制数
inetAton 将 IP 地址转换为数字表示,IP 值需要加上引号
inetNtoa 将数字 n 转换成 IP 的形式

select 列计算

示例 1:

列计算的 加减乘除 对应的方法分别为:add / subtract / multiply / divide

其查询生成的 Sql 如下:

示例 2:

其查询生成的 Sql 如下:

示例 3:

其查询生成的 Sql 如下:

select 取相反数

select case...when

示例 1:

其查询生成的 Sql 如下:

SQL 执行的结果如下:

示例 2:

其查询生成的 Sql 如下:

提示

在以上示例中,由于 case else 属于 Java 关键字,无法使用其进行方法命名,因此会添加一个下划线小尾巴 "_" 变成 case_ else_ ,这是无奈之举。 在以后的 QueryWrapper 构建中,遇到 java 关键字也会采用类似的解决方法。

with...select

示例 1:

生成的 SQL 如下:

示例 2:

生成的 SQL 如下:

with recursive...select

示例 1:

生成的 SQL 如下:

示例 2:

生成的 SQL 如下:

where

其查询生成的 Sql 如下:

where 动态条件

注意

QueryWrapper条件构建中,若参数为null时默认会被忽略,不会拼接查询条件

方式1:when()

其查询生成的 Sql 如下:

方式2:使用重载方法

对当前条件参数进行判断:

框架提供了工具类 If ,包含常用的判断方法(如非空、非空集合、非空字符串等),供开发者简化代码:

上述代码生成的 Sql 如下:

where 使用 SQL 函数

你可以通过使用 QueryMethods 类下的函数实现 where 对指定列运算后作为条件进行查询(QueryMethods 位于 mybatisflex.core.query 下)。

其查询生成的 Sql 如下:

where select

其查询生成的 Sql 如下:

where exists, not exists

其查询生成的 Sql 如下:

and (...) or (...)

其查询生成的 Sql 如下:

自定义字符串列名

其查询生成的 Sql 如下:

以上 SQL 的 Java 代码也可以简写为:

注意,以上代码需要静态导入 QueryMethods.column 方法:

group by

其查询生成的 Sql 如下:

having

其查询生成的 Sql 如下:

orderBy

其查询生成的 Sql 如下:

orderBy 动态排序

其查询生成的 Sql 如下:

hint

Hint 是数据库厂商(比如 Oracle、MySQL、达梦等)提供的一种 SQL语法,它允许用户在 SQL 语句中插入相关的语法,从而影响 SQL 的执行方式。 它是一种【非常规】的直接影响优化器、指定执行计划的 SQL 优化手段。

其查询生成的 Sql 如下:

join(left join,inner join...)

其查询生成的 Sql 如下:

join on 多个条件

其查询生成的 Sql 如下:

join select

其查询生成的 Sql 如下:

join 自己

其查询生成的 Sql 如下:

tb_account 表带有逻辑删除,那么其生成的 SQL 如下:

关于逻辑删除更多文档请参考 这里

union, union all

其查询生成的 Sql 如下:

limit... offset

提示

在 "limit... offset" 的示例中,MyBatis-Flex 能够自动识别当前数据库👍,并根据数据库的类型生成不同的 SQL,用户也可以很轻易的通过 DialectFactory 注册(新增或改写)自己的实现方言。

MySQL 下执行的代码如下:

PostgreSQL 下执行的代码如下:

Informix 下执行的代码如下:

Oracle 下执行的代码如下:

Db2 下执行的代码如下:

Sybase 下执行的代码如下:

Firebird 下执行的代码如下:

Lambda 扩展

简单示例:

SQL 输入内容如下:

稍微复杂点的示例:

SQL 输入内容如下:

MyBatis-Plus 兼容 API ^ v1.7.2

从 MyBatis-Flex v1.7.2 开始,QueryWrapper 添加了一系列对 MyBatis-Plus 兼容的 API,方便喜欢 MyBatis-Flex 用户从 MyBatis-Plus 迁移到 MyBatis-Flex。

示例代码如下:

以上代码内容,输出的 SQL 如下:

以上的 API 虽然尽量兼容 MyBatis-Plus,但也有所不同,需要用户注意以下几点:

注意点 1:

对于 eq() ne() ... 等方法的忽略条件判断,MyBatis-Plus 在第一个参数,而 MyBatis-Flex 在 最后一个 参数。例如:

MyBatis-Plus 的写法:

MyBatis-Flex 的写法:

注意点 2:

对于 likeLeft likeRight notLikeLeft notLikeRight 这 4 个方法,MyBatis-Flex 和 MyBatis-Plus 是相反的。

例如:

MyBatis-Plus 生成的 where 条件是:

而 MyBatis-Flex 生成的 where 条件是:

因此,假设数据表的内容如下:

相同的代码 qw.likeLeft("name", "3") ,MyBatis-Flex 匹配到的内容是 345 ,而 MyBatis-Plus 匹配到的内容是 123

Entity 转化为 QueryWrapper

QueryWrapper 提供了 create() 方法帮助用户把 entity 转化为 QueryWrapper。

简单示例:

输出的 SQL 内容如下:

自定义 Entity 字段的 SQL 操作符示例:

输出的 SQL 内容如下:

Map 转化为 QueryWrapper

方法同 Entity 转化为 QueryWrapper 类似,只需要把 entity 变量替换为 map 即可。

QueryWrapper 序列化

QueryWrapper 中,由于其定义了 循环引用 的一些数据结构,同时,其很多属性都是 private 或者 protected 修饰且没有 getter setter 方法, 这会导致使用一些 json 库在序列化的过程中,出现问题;但这些问题并非 QueryWrapper 的问题,而是序列化框架的问题。

因此,我们在使用序列化框架时,需要注意其是否支持这些特征,比如在使用 FastJson2 序列化时,需要添加以下配置:

序列化:

反序列化:

Gson Jackson 等其他框架需要自行参考其文档添加相关配置;另外,我们更加建议使用专业的序列化工具去进行序列化,而非使用 json,比如使用 JDK Serial 或者 fst 等。 以下是相关的序列化示例代码:

JDK Serial 序列化:

JDK Serial 反序列化:

fst 序列化 和 反序列化:

QueryWrapper 克隆

当我们想对 QueryWrapper 进行改造而不想影响之前构建出来的 QueryWrapper 时,可以使用 clone() 方法,克隆出来一份 QueryWrapper 进行操作,示例:

特别注意事项!!!

在 QueryWrapper 的条件构建中,如果传入 null 值,则自动忽略该条件,这有许多的好处,不需要额外的通过 when() 方法判断。但是也带来一些额外的知识记忆点, 因此,正对这一点需要特别注意一下。

例如:

在以上的 query1 中,由于 userName id 都为 null,MyBatis-Flex 会自动忽略 null 值的条件,因此,它们构建出来的 SQL 条件是和 query2 完全一致的 。

QueryColumnBehavior ^ v1.5.7

在以上的内容中,我们知道 MyBatis-Flex 会自动忽略 null 值的条件,但是在实际开发中,有的开发者希望除了自动忽略 null 值以外,还可以自动忽略其他值,内置的规则有 null (默认) 、 空字符串 空白字符串 ,当然也可以自定义。

此时,我们可以通过配置 QueryColumnBehavior 来自定义忽略的值。

另外,在某些场景下,开发者希望在构建 QueryWrapper 中,如果传入的值是集合或数组,则使用 in 逻辑,否则使用 = (等于) 逻辑:

当添加以上配置时,我们在构建 QueryWrapper 的 in 的 SQL 时,逻辑如下:

输出的 SQL 如下:

ids 只有 1 个值时,逻辑如下: