跳到主要内容

语句生成规则

本章介绍如何使用 SQL 增强规则来简化动态 SQL 开发。相比 XML 标签,它们能更智能地处理空参数、连接符(AND/OR)和逗号分隔符。

规则描述
@{and} / @{ifand}智能追加 AND 条件。
@{or} / @{ifor}智能追加 OR 条件。
@{in} / @{ifin}展开集合参数为 IN (v1, v2)
@{set} / @{ifset}智能处理 UPDATE 语句的 SET 逗号。
@{if} / @{iftext}通用条件判断(解析 / 直出)。
@{case} / @{when} / @{else}多路分支 (Switch / If-Else)。
@{macro} / @{ifmacro}引用预定义的 SQL 宏片段。
@{md5}计算参数 MD5 值。
@{uuid32} / @{uuid36}生成 UUID。
@{pairs}遍历 Map/List 生成参数模版。

AND、IFAND 规则

解决 WHERE 子句中动态拼接 AND 条件的问题。

  • @{and, ...}:当包含的 SQL 片段生成了非空参数(或包含 ${...} 注入)时,自动追加该片段。
  • @{ifand, test, ...}:当 test 表达式为真时,应用后续逻辑。

特性说明

  1. 自动前缀去除:规则会自动处理 WHERE 关键字和最前面多余的 AND,例如 WHERE @{and, AND x=1} 会优化为 WHERE x=1
  2. 智能空值丢弃
    • 默认情况下,如果 @{and, col=:val} 中的 :val 为空 (null),则整个片段会被丢弃。
    • 例外:如果片段中包含 ${...} 动态注入,即使参数为空,该片段也会被强制保留(防止误删筛选逻辑)。

示例

示例status 必填,userId 选填。无需手动处理 WHERE/AND 连接符。

select * from users 
where status = :status -- 固定条件
@{and, uid = :userId} -- 自动处理 AND 前缀
-- 仅当 userId 不为空且长度>0 时生效
@{ifand, userId != null && userId.length() > 0, uid = :userId}
生成的 SQL (status=1, userId='abc')
select * from users
where status = ? and uid = ?
智能特性
  • 自动补全 WHERE:若规则位于条件首位,会自动补全 WHERE 关键字。
  • 自动处理前缀:智能识别上下文,自动去除或添加必要的 AND
  • 自动降级:若前文是 OR,会自动适配。

OR、IFOR 规则

解决 WHERE 子句中动态拼接 OR 条件的问题。

  • @{or, ...}:当包含的 SQL 片段生成了非空参数时,自动追加该片段。
  • @{ifor, test, ...}:当 test 表达式为真时,应用后续逻辑。

示例:匹配用户名或邮箱。自动处理 OR 连接符。

select * from users 
where username = :username
@{or, email = :email} -- 自动以 OR 连接
-- 仅当 email 包含 '@' 时生效
@{ifor, email != null && email.contains("@"), email = :email}
生成的 SQL (username='admin', email='a@b.c')
select * from users
where username = ? or email = ?
智能特性

与 AND 规则一致,具备自动补全 WHERE 和自动修正连接符(OR)的能力。


IN、IFIN 规则

用于简化 IN 子句的拼接,自动展平集合参数。

  • @{in, ...}:自动将集合/数组参数展平为 (?, ?, ...)
  • @{ifin, test, ...}:当 test 表达式为真时生效。

示例:查询 ID 在列表中的用户。

select * from users
where status = :status
@{in, and id in :ids} -- 自动展开为 id in (?,?,?)
-- 仅当 ids 集合非空时生效
@{ifin, ids != null && ids.size() > 0, and id in :ids}
生成的 SQL (ids=[1,2,3])
select * from users
where status = ? and id in (?, ?, ?)
注意事项

本规则不会自动补全 AND/OR 前缀,需在规则内手动写明(如示例中的 and id in ...)。


SET、IFSET 规则

专用于 UPDATE 语句,解决动态列更新时的逗号拼接问题。

  • @{set, ...}:参数非空时追加赋值,并自动管理逗号。
  • @{ifset, test, ...}:当 test 表达式为真时生效。

示例:更新用户,status 为选填。

update users 
set update_time = now() -- 固定列
@{set, status = :status} -- 自动处理逗号
-- 仅当 status != 'disabled' 时更新
@{ifset, status != null && status != 'disabled', status = :status}
where uid = :uid
生成的 SQL (status='Active')
update users 
set update_time = now(), status = ?
where uid = ?

使用技巧

当在 @{set} 规则之间混合使用手动 SQL(例如 fixed_col = 1)时,无需手动添加逗号。 规则引擎会自动检测前文内容并智能补充逗号。手动添加逗号反而可能在某些动态场景下导致语法错误。

推荐写法(规则放到最后)
update user
fixed_col = 1 -- 结尾不要加逗号
@{set, name = :name} -- 规则会自动处理前置逗号(生成 ", name = ?")
@{set, age = :age}
问题写法(当规则没有匹配时)
UPDATE tb_user SET
@{set, name = :name}, -- ❌ 规则无法删除身后的逗号
fixed_col = 123,
@{set, email = :email} -- ❌ 规则虽然不会添加新的逗号但也不会删除上一个条件中的逗号
WHERE id = :id

IF、IFTEXT 规则

通用条件判断规则。当 test 表达式为真时,将 content 包含在最终 SQL 中。

虽然功能类似,但两者对 content 内容的处理方式截然不同:

  • @{if, test, content}智能解析。会对 content 进行完整解析,支持嵌套其他动态规则(如 @{in})、参数占位符等。这是最常用的方式。
  • @{iftext, test, content}原生直出。不对 content 做任何解析,直接原样拼接到 SQL 中。用于注入特殊关键字或不支持参数化的语法片段。
select * from users where 1=1
-- 1. 普通 @{if}:支持解析内部的 @{in} 和参数 :name
@{if, hasName, and name = :name}
@{if, idList != null, and id in @{in, :idList}}

-- 2. 原生 @{iftext}:原样注入 SQL 片段(不解析参数)
@{iftext, status > 2, and age = 36 }
生成的 SQL (hasName=true, idList=[1,2], status=3)
select * from users where 1=1
and name = ? -- @{if} 正常解析参数
and id in (?, ?) -- @{if} 允许嵌套 @{in}
and age = 36 -- @{iftext} 原样拼接

CASE、WHEN、ELSE 规则

提供 SQL 生成阶段的分支逻辑,支持 Switch (值匹配) 和 If-Else (条件匹配) 两种模式。

值匹配@{case} 第一个参数为变量。

select * from users where @{case, userType, 
@{when, 'admin', role = 'administrator'},
@{when, 'manager', role = 'manager'},
@{else, role = 'visitor'}
}
生成的 SQL (userType='admin')
select * from users
where role = 'administrator'
使用须知
  • 模式切换:通过第一个参数是否存在来切换 Switch / If-Else 模式。
  • Else@{else} 必须写在最后。
  • 默认值:若无匹配且无 else,输出空字符串。

MACRO、IFMACRO 规则

用于将预先定义的 SQL 片段(宏)包含进最终 SQL 中,类似于 XML 映射文件中的 <include> 标签。

  • @{macro, name}:引用名称为 name 的 SQL 宏。
  • @{ifmacro, test_expr, name}:当 test_expr 为真时,引用名称为 name 的 SQL 宏。

1. 注册宏 (Java)

// 在 API Binder 或 Registry 中注册
registry.addMacro("includeSeq", "and seq = :seq");

2. 引用宏 (SQL)

select * from users where
status = :status
@{macro, includeSeq} -- 引用宏
@{ifmacro, status > 2, includeSeq} -- 条件引用
生成的 SQL (status=3)
select * from users
where status = ? and seq = ?
注意事项

引用一个不存在的 SQL 宏会导致执行报错。


MD5 规则

对参数进行 MD5 计算。

  • @{md5, expr}:对 expr 表达式结果进行 MD5 计算,并将结果作为 SQL 参数。

示例:对密码进行 MD5 加密匹配。

select * from users 
where account = :loginName
and password = @{md5, loginPassword}
生成的 SQL
select * from users
where account = ? and password = ? -- 参数值为 MD5(loginPassword)

UUID 规则

自动生成 UUID 并作为 SQL 参数。

  • @{uuid32}:生成 32 长度 UUID (无-分隔符)。
  • @{uuid36}:生成 36 长度 UUID (带-分隔符)。

示例:插入时自动生成 ID。

insert into users (id, uid, name, time) 
values (:id, @{uuid32}, :name, now());
生成的 SQL
insert into users (id, uid, name, time) 
values (?, ?, ?, now()); -- 第二个参数为生成的 UUID

PAIRS 规则

用于遍历集合(Map/List/Array)并按模版生成 SQL 片段。

  • @{pairs, collection, template}:遍历 collection,对以每个元素应用 template

模版变量

  • :k:Map 的 Key 或 List/Array 的索引。
  • :v:Map 的 Value 或 List/Array 的元素值。
  • :i:当前索引(从 0 开始)。

示例:将 Map 数据写入 Redis HASH 结构。

-- 假设参数 arg0 是一个 Map: {"field1": "val1", "field2": "val2"}
HSET myKey1 @{pairs, :arg0, :k :v}
生成的命令
HSET myKey1 field1 val1 field2 val2