即将开始使用jOOQ进行概念验证。 jOOQ看起来非常简单,富有表现力,使SQL维护变得更加容易。
我们是一家Java 8商店。这里的用例是为报表应用程序编写数据层,该应用程序根据屏幕上的用户选择动态查询表,列,过滤器和函数。
虽然我非常喜欢编写类型安全查询(使用jOOQ codegen)的想法,但我认为对于我的用例,它不是最合适的。因为表,列等是完全未知的,我想我只需要jOOQ SQL构建器。这意味着我必须放弃类型安全。我的评估是否正确?或者我是否可以使用任何模式来构建"动态" SQL在不影响类型安全的情况下?任何指针都会非常感激。
答案 0 :(得分:2)
您不必使用jOOQ的代码生成器来充分利用jOOQ中的大多数功能。手册的介绍部分指出,jOOQ可以很容易地用作SQL构建器,而不需要代码生成器提供的额外类型静态安全性:
https://www.jooq.org/doc/latest/manual/getting-started/use-cases/jooq-as-a-standalone-sql-builder
代码生成器本质上提供了两种类型的安全元素:
这些确实有助于开发您的应用程序
...但要注意代码生成器只是反向设计架构的静态快照。它是类型安全的,因为整个jOOQ API允许这种类型的安全性。例如,Field<T>
类型具有泛型类型<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();
正如您所看到的,与使用代码生成器相比,唯一改变的是表/列引用。
但这意味着,没有代码生成器,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();
您也可以使用&#34;功能方式&#34;:
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
正如您所看到的,虽然代码生成器确实为静态模式添加了很多值,但在jOOQ API中没有什么是静态的。 jOOQ是一个用于动态SQL查询构造的API,它恰好也适用于静态查询。