跳到主要内容

3.4 预设 SQL(Key-SQL)

概念

预设 SQL 是将 SQL 语句预先定义好,通过唯一的 key 来调用。

优势:

  1. SQL 集中管理,便于维护
  2. 支持动态条件,灵活组装
  3. 可从数据库表统一加载(当前在初始化时读取,修改后需重新初始化才能通过公共 API 生效)
  4. 支持 SQL 嵌套复用

配置方式

方式一:XML 配置文件

# application.yml
dlz:
db:
sqllist: [app/*] # 预设 SQL 文件路径

resources/sql/app/ 下创建 SQL 文件:

<?xml version="1.0" encoding="UTF-8" ?>
<sqlList>
<!-- 基础查询 -->
<sql sqlId="key.user.findActive"><![CDATA[
SELECT * FROM user WHERE 1=1
[AND status = #{status}]
[AND name LIKE #{name}]
]]></sql>

<!-- SQL 嵌套 -->
<sql sqlId="key.condition.age"><![CDATA[
age > #{minAge} [AND age < #{maxAge}]
]]></sql>

<sql sqlId="key.user.findByAge"><![CDATA[
SELECT * FROM user WHERE 1=1
AND ${key.condition.age}
]]></sql>
</sqlList>

方式二:数据库配置

开启 use-db-sql 后,框架初始化时执行 dlz.db.sql 配置的查询;默认查询从 sys_sql.sql_key/sql_value 读取并别名为 k/s。例如可用项目自己的 Entity 或参数化 SQL 维护该表:

DB.jdbc.execute(
"INSERT INTO sys_sql (sql_key, sql_value) VALUES (?, ?)",
"user.findActive",
"SELECT * FROM user WHERE 1=1 [AND status = #{status}]");

SysSql 不是 DLZ-DB 公共模型;如果项目要使用 Entity 管理这张表,需自行定义。当前公共 API 也没有预设 SQL 热重载入口,不应宣称修改数据库记录后无需重启就会立即生效。

使用方式

// 基础查询
List<User> users = DB.sql.selectWrapper("key.user.findActive")
.addPara("status", 1)
.addPara("name", "张")
.queryList(User.class);

// 分页查询
Page<User> page = DB.sql.selectWrapper("key.user.findActive")
.addPara("status", 1)
.page(1, 10)
.queryPage(User.class);

// 数据库中的预设 SQL
DB.sql.selectWrapper("key.test.user.find")
.addPara("status", 1)
.queryList();

空值处理

方括号 [...] 内的条件:参数为空时自动忽略。

// status 有值,name 和 minAge 为空
DB.sql.selectWrapper("key.user.findActive")
.addPara("status", 1) // 有值,生效
.addPara("name", null) // 空值,忽略
.addPara("minAge", null) // 空值,忽略
.queryList(User.class);

// 生成 SQL:SELECT * FROM user WHERE 1=1 AND status = 1

规则

  • XML 配置的 sqlId 按原值存储,必须与 Java 调用使用的 key 一致;按当前规则应以 "key." 开头
  • 数据库查询加载的 k 值和 DB.config.sql(...) 参数可以不带 "key.",这两个入口会自动补上前缀
  • 支持 SQL 嵌套:${key.xxx} 引用并展开其他预设 SQL;这是 SQL 片段替换,不是 #{参数名} 参数绑定