这是一个实验性功能,因此可能会发生变化。使用风险自负!
替换
适用于 ❌ 开源版 ✅ Express 版 ✅ 专业版 ✅ 企业版
转换 SQL 的一个非常强大的方法是使用 org.jooq.QueryPart
API 的 QueryPart.replace()
API,将任何表达式树中的特定 org.jooq.QueryPart
元素替换为其他内容。此 API 将表达式树视为持久化数据结构,即生成的树可能包含现有树的部分,但不会修改现有树。
假设您希望实现一个优化引擎,该引擎删除冗余的 SQL 子句。例如,表达式 NOT(NOT(p))
可以在标准 SQL 中替换为 p
(在某些没有标准 BOOLEAN
类型支持的“聪明”方言中,它可能不完全相同)
// Contains redundant operators Condition c = not(not(BOOK.ID.eq(1))); System.out.println(c); System.out.println(c.$replace(q -> q instanceof QOM.Not n1 && n1.$arg1() instanceof QOM.Not n2 ? n2.$arg1() : q ));
以上打印
not (not ("BOOK"."ID" = 1)) "BOOK"."ID" = 1
替换算法将尝试在您的树上递归运行替换函数,直到它不再影响树。这意味着两件事
- 您可以在一个函数中实现所有替换逻辑,适用于各种规则。规则的应用顺序是您在函数中定义的顺序。
- 只有在没有更多规则适用时,算法才会停止。如果两个规则分别转换
A > B
和B > A
,则该算法可能永远不会停止。
这是一个更复杂的示例,它使用 println()
调用记录替换
// Contains redundant operators Condition c = not(not(not(BOOK.ID.ne(1)))); QueryPart result = c.$replace(q -> { if (q instanceof QOM.Not n1 && n1.$arg1() instanceof QOM.Not n2) { System.out.println("Replacing NOT(NOT(p)) by NOT(p): " + q); return n2.$arg1(); } else if (q instanceof QOM.Not n1 && n1.$arg1() instanceof QOM.Ne<?> n2) { System.out.println("Replacing NOT(x != y) by x = y: " + q); return n2.$arg1().eq((Field) n2.$arg2()); } return q; })); System.out.println("Result: " + result);
输出是
Replacing NOT(x != y) by x = y: not ("BOOK"."ID" <> 1) Replacing NOT(NOT(p)) by NOT(p): not (not ("BOOK"."ID" = 1)) Result: "BOOK"."ID" = 1
如您所见
- 替换函数被多次调用。
- 第二次调用可以作用于第一次调用的结果,其中
NOT (x != y)
谓词已经得到改进。 - 替换以递归方式工作,深度优先,自下而上。
- 当不再进行替换时,它就会停止。
当您使用 jOOQ 的 解析器时,这显然也有效,并且通过 解析连接使用时非常有用,例如,优化任何类型的基于 JDBC 或 R2DBC 的应用程序!
// Contains redundant operators Condition c = create.parser().parseCondition("not not not book.id != 1"); QueryPart result = c.$replace(q -> { if (q instanceof QOM.Not n1 && n1.$arg1() instanceof QOM.Not n2) { System.out.println("Replacing NOT(NOT(p)) by NOT(p): " + q); return n2.$arg1(); } else if (q instanceof QOM.Not n1 && n1.$arg1() instanceof QOM.Ne<?> n2) { System.out.println("Replacing NOT(x != y) by x = y: " + q); return n2.$arg1().eq((Field) n2.$arg2()); } return q; })); System.out.println("Result: " + result);
结果完全相同
Replacing NOT(x != y) by x = y: not (book.id <> 1) Replacing NOT(NOT(p)) by NOT(p): not (not (book.id = 1)) Result: book.id = 1
从 jOOQ 3.17 开始,也可以使用监听 replacer来实现此日志记录。
内置 replacer
以下各节展示了一些内置 replacer 的示例。
限制
就像 模型 API 遍历一样,replacer 无法遍历到“不透明”的 org.jooq.QueryPart
实例中,包括 自定义 QueryParts 或 纯 SQL 模板。另请参阅需要代码生成的功能了解更多详情。
反馈
您对此页面有任何反馈吗? 我们很乐意听取您的意见!