即将开始使用 jOOQ 进行概念验证。 jOOQ 看起来非常简单、富有表现力,并且使 SQL 维护变得更加容易。
我们是一家 Java 8 商店。这里的用例是为报告应用程序编写数据层,该应用程序根据屏幕上的用户选择动态查询表、列、过滤器和函数。
虽然我真的很喜欢编写类型安全查询(使用 jOOQ codegen)的想法,但我认为对于我的用例来说,这不是最合适的。因为表、列等完全未知,我想我只需要 jOOQ SQL 构建器。这意味着我必须放弃类型安全。我的评估正确吗?或者是否有任何模式可以用来构建“动态”SQL 而不会影响类型安全?任何指示将不胜感激。
最佳答案
您不必使用 jOOQ 的代码生成器即可利用 jOOQ 中的大多数功能。该手册的介绍部分指出,jOOQ 可以轻松用作 SQL 构建器,而无需代码生成器提供的额外类型静态安全性:
https://www.jooq.org/doc/latest/manual/getting-started/use-cases/jooq-as-a-standalone-sql-builder
代码生成提供的类型安全
代码生成器本质上提供两种类型的安全元素:
- 对象的名称被硬连接到类名称(表、架构、序列、数据类型、过程等)和属性名称(列、类型属性、过程参数)中。
- 属性类型(列、属性、参数)被硬连接到通用属性定义中。
这些东西肯定有助于开发您的应用程序
jOOQ API 提供的类型安全
...但请注意,代码生成器只是对架构的静态快照进行反向工程。它是类型安全的,因为整个 jOOQ API 允许这种类型安全。例如, Field<T>
type 有一个泛型类型 <T>
,也可以在没有代码生成器的情况下使用,例如通过使用 plain SQL APIs :
Field<String> firstName = field(name("USER", "FIRST_NAME"), SQLDataType.VARCHAR(50));
上述 API 用法 ( DSL.field(Name, DataType)
) 的作用与代码生成器的作用大致相同。它创建一个列引用,并附加列类型信息。您可以像代码生成器生成的列一样使用它:
DSL.using(configuration)
.select(firstName)
.from(name("USER"))
.where(firstName.like("A%")) // Compiles
.and(firstName.eq(1)) // Doesn't compile: firstName must be compared to String
.join(name("ADDRESS")) // Doesn't compile: the SQL syntax is wrong
.fetch();
如您所见,与使用代码生成器相比,唯一改变的是表/列引用。
动态 SQL
但这意味着,如果没有代码生成器,jOOQ 对您来说会更加强大。您仍然可以非常轻松地创建动态 SQL 语句。例如:
// Construct your SQL query elements dynamically, and type safely
Condition condition = hasFirstNameFilter()
? firstName.like("A%")
: DSL.trueCondition();
DSL.using(configuration)
.select(firstName)
.from(name("USER"))
.where(condition) // Use dynamically constructed element here
.fetch();
您也可以通过“功能性方式”执行此操作:
DSL.using(configuration)
.select(firstName)
.from(name("USER"))
.where(condition()) // Call a function to create the condition here
.fetch();
或者更好
public static Select<Record1<String>> firstNames(
Function<? super Field<String>, ? extends Condition> condition
) {
return
DSL.using(configuration)
.select(firstName)
.from(name("USER"))
.where(condition.apply(firstName)); // Lazy evaluate the predicate here
}
// Use it like this:
firstNames(col -> col.like("A%")).fetch();
或者甚至更好,将上面的函数设为高阶函数:
public static Function<
? super Function<? super Field<String>, ? extends Condition>,
? extends Select<Record1<String>>
> firstNames() {
// Lazy construct query here
return f -> DSL.using(configuration)
.select(firstName)
.from(name("USER"))
.where(f.apply(firstName)); // Lazy evaluate the predicate here
}
// Use it like this:
firstNames().apply(col -> col.like("A%")).fetch();
更多详细信息请参见此处: https://www.jooq.org/doc/latest/manual/sql-building/dynamic-sql
结论:
正如您所看到的,虽然代码生成器确实为静态模式增加了很多值(value),但 jOOQ API 中并没有真正静态的东西。 jOOQ 是一个用于动态 SQL 查询构造的 API,它恰好也适用于静态查询。
关于sql - 用于报告应用程序的动态 SQL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43586452/