跳到主要内容

SQL 增强规则

该类规则特点是可以完成部分不太复杂的的动态 SQL,比如:入参不为空时才会正式成为 SQL 参数。下面是本类中所含有的具体规则:

规则描述
@{and, queryExpr}AND 规则,当 queryExpr 条件 SQL 片段中生成了不为空的条件参数时,条件表达式会被加入到最终 SQL 语句中。
@{ifand, testExpr, queryExpr}testExpr 条件表达式为真时 queryExpr 才会以 AND 规则方式处理 queryExpr 条件。
@{or, queryExpr}OR 规则,当 queryExpr 条件 SQL 片段中生成了不为空的条件参数时,条件表达式会被加入到最终 SQL 语句中。
@{ifor, testExpr, queryExpr}testExpr 条件表达式为真时 queryExpr 才会以 OR 规则方式处理 queryExpr 条件。
@{in, queryExpr}IN 规则,在规则中 queryExpr 表达式中只能出现一个参数,当参数不为空时候会自动为其转换为 (?,?,?,) 形式的查询条件。
@{ifin, testExpr, queryExpr}增强的 IN 规则,当 testExpr 条件表达式为真时才会以 IN 规则机制处理 queryExpr 条件语句。
@{set, queryExpr}SET 规则,可以简化在 update 语句中 set 字句部分里当有数据时候才进行更新的实现复杂问题。
@{ifset, testExpr, queryExpr}增强的 SET 规则,当 testExpr 条件表达式为真时才会以 SET 规则机制处理 queryExpr 条件语句。

AND、IFAND 规则

借助 AND 规则可以实现,条件不为空时才将条件语句追加到 SQL 中,而 IFAND 增加了一个条件表达式作为判断条件。

例如,当一个参数不为空时才会被当作 SQL 条件的场景在使用规则前后不同用法下的差异:

使用规则传参
select * from users 
where status = :status -- 条件 status
@{and, uid = :userId} -- 条件 uid
等效代码:XML Mapper
<select id="queryUser">
select * from users
where status = #{status}
<if test="userId != null">
and uid = #{userId}
</if>
</select>

<!-- 即便是 Mapper 也可以使用规则哦 -->
<select id="queryUser">
select * from users
where status = #{status} @{and, uid = :userId}
</select>
等效代码:Java Code
// 准备 SQL 和参数
String querySQL = "select * from users where status = ?";
Object queryArg = null;
if (userId != null) {
querySQL = querySQL + " and uid = ?";
queryArg = new Object[]{ 1, userId};
} else {
queryArg = new Object[]{ 1};
}

// 执行查询
jdbc.queryForList(querySQL, queryArg);

使用 IFAND 规则允许通过一个表达式来判断是否使用这个规则,相比 AND 规则具有更高的灵活性。

编程方式:规则中设置启用条件
select * from users 
where status = :arg0
@{ifand, arg1 != null, uid = :arg1}
  • 通过 arg1 != null 激活条件决定是否使用规则。
XML 方式:规则中设置启用条件
<select id="queryUser">
select * from users
where status = #{status} @{ifand, userId != null, uid = :userId}
</select>
  • 通过 userId != null 激活条件决定是否使用规则。
信息

@{and}@{ifand} 规则可以自适应以下 SQL 语句场景。

select * from users @{and, uid = :userId} -- 自动补全 where 字句
select * from users where @{and, uid = :userId} -- 如果条件为空 where 不会被消除
select * from users where status = :status @{and, uid = :userId} -- 自动补全 and
select * from users where status = :status and @{and, uid = :userId} -- 如果条件为空 and 不会被消除
select * from users where status = :status or @{and, uid = :userId} -- 会自动降级为 or 规则

OR、IFOR 规则

  • OR、IFOR 和 AND、IFAND 规则非常相似,不同的是条件的前后连接使用 or 关键字作为连接。具体用法可以参考 AND 规则用法。

IN、IFIN 规则

利用 IN 规则可以简化 SQL 中 in 语句拼接的需要,而 IFIN 增加了一个条件表达式作为判断条件。

例如,生成带有多个参数的 in 语句在不同方式下使用规则的前后对比:

使用规则生成 in 语句
select * from users where status = :arg0
@{in,and id in :arg1} -- 生成 id in (?,?,?)
等效代码:XML Mapper
<select id="queryUser">
select * from users
where status = #{status}
<if test="ids != null && ids.length > 0">
and id in
<foreach collection="ids" item="item" index="index" open="(" separator="," close=")">
#{item}
</foreach>
</if>
</select>

<!-- 即便是 Mapper 也可以使用规则哦 -->
<select id="queryUser">
select * from users
where status = #{status} @{in,and id in :ids}
</select>
等效代码:Java Code
// 准备 SQL 和参数
StringBuilder querySQL = new StringBuilder("select * from user_info where status =?");
List<Object> queryArgs = new ArrayList<>();
queryArgs.add("1");

Object[] ids = new Object[] { 1, 2, 3 };
if (ids != null && ids.length > 0) {
querySQL.append("and id in (");
for (int i = 0; i < ids.length; i++) {
if (i == 0) {
querySQL.append("?");
} else {
querySQL.append(", ?");
}
queryArgs.add(ids[i]);
}
querySQL.append(")");
}

// 执行查询
jdbc.queryForList(querySQL.toString(), queryArgs.toArray());

IFIN 规则允许通过一个表达式来判断是否使用这个规则,相比 IN 规则具有更高的灵活性。

在编程方式中使用 IFIN 规则
select * from users where status = :arg0
@{ifin, arg1.size() > 2 , and id in :arg1}
  • 只有当条件参数数量大于 2 时才激活 IN 规则添加 in 条件。
在 XML 方式中使用 IFIN 规则
<select id="queryUser">
select * from users
where status = #{status} @{in, ids.size() > 2 ,and id in :ids}
</select>
  • 只有当条件参数数量大于 2 时才激活 IN 规则添加 in 条件。
信息

IN 规则限制是:

  • 一次只能处理一个 in 条件。
  • IN 规则不支持自动补全 and、or、where 等可能缺失的查询关键字,如:
    • select * from users @{in,id in :ids} 将会产生错误的 SQL。
信息

IN 规则可以处理的参数类型有:

  • 单个对象
  • 通过 SqlArg 包装的集合或数组参数
  • 数组
  • 任何派生自 Iterable 接口的子类,包括:Collection、List、Set 类型。

SET、IFSET 规则

利用 SET 规则可以简化在 update 语句中 set 字句部分里更新字段如果为空时不参与更新的实现逻辑,而 IFSET 则增加了一个条件表达式作为判断条件。

下面是在使用不用方式中使用规则的前后对比:

使用规则生成:SET 字句
update users 
set update_time = now() -- 更新字段 update_time
@{set, status = :arg0} -- 更新字段 status,当 arg0 不为空时有效(规则会自动处理逗号问题)
where uid = :arg1
等效代码:XML Mapper
<update id="updateUser">
update users
set update_time = now()
<if test="status != null">, status = #{status}</if>
where
uid = #{uid}
</update>

<!-- 即便是 Mapper 也可以使用规则哦 -->
<update id="updateUser">
update users
set update_time = now()
@{set, status = :status}
where
uid = #{uid}
</update>
等效代码:Java Code
// 准备 SQL 和参数
StringBuilder querySQL = new StringBuilder("update users set update_time = now()");
List<Object> queryArgs = new ArrayList<>();

if (status != null) {
querySQL.append(", status = ?");
queryArgs.add(status);
}
querySQL.append(" where uid =?");
queryArgs.add(uid);

// 执行查询
jdbc.executeUpdate(querySQL.toString(), queryArg.toArray());

IFSET 规则允许通过一个表达式来判断是否使用这个规则,相比 SET 规则具有更高的灵活性。

在编程方式中使用 IFIN 规则
update users
set update_time = now()
@{ifset, arg0 != 2 ,status = :arg0}
where uid = :arg1
  • 只有当条件参数 status 不等于 2 时才会被当作更新项目。
在 XML 方式中使用 IFIN 规则
<update id="queryUser">
update users
set update_time = now()
@{ifset, status != 2 ,status = :status}
where
uid = #{uid}
</update>
  • 只有当条件参数 status 不等于 2 时才会被当作更新项目。