网络知识 娱乐 jOOQ API中的 "字符串 "是什么?

jOOQ API中的 "字符串 "是什么?

jOOQ最大的优势之一是它是一个类型安全的SQL API。"类型安全",在这里,意味着你放在jOOQ查询中的每个对象都有一个定义好的类型,比如:

  • [Condition](https://www.jooq.org/javadoc/latest/org.jooq/org/jooq/Condition.html)
  • [Field](https://www.jooq.org/javadoc/latest/org.jooq/org/jooq/Field.html)
  • [Table](https://www.jooq.org/javadoc/latest/org.jooq/org/jooq/Table.html)

这些可以在jOOQ中以类型安全的方式使用,如:

ctx.select(T.A) // A Field .from(T) // A Table .where(T.B.eq(1)) // A Condition .fetch();复制代码

然而,在一些情况下,无论出于什么原因,你想绕过类型安全,包括扩展jOOQ,例如使用普通的SQL模板。在这些情况下,你会传递一个 "字符串 "对象给jOOQ API。但不是每一个这样的字符串对象都是一样的。有哪些不同类型的字符串?在jOOQ API中,有4种主要的字符串类型。

1.绑定值

最明显的字符串类型是绑定值或字面意义。你可以使用明确地创建这些:

// As always, this static import is impliedimport static org.jooq.impl.DSL.*;Field<String> bind = val("abc");Field<String> literal = inline("xyz");复制代码

默认情况下,第一个值会在生成的SQL中产生一个绑定参数标记"?" ,而第二个值会产生一个转义的字符串字面'xyz' 。你可能已经在隐含地这样做了。每当你传递一个String ,而jOOQ API期望的是一个T ,你就会隐含地使用String 来包装你的值。 DSL.val(T):

ctx.select(T.A) .from(T) .where(T.C.eq("xyz")) // Implicit bind value .fetch();复制代码

这仍然是一个String 值的类型安全用法,因为它确实被包装成了一个Field<String>。

2.普通SQL模板

每当jOOQ缺少一些供应商的特定功能时,后门就是使用普通SQL模板。你可以为最流行的类型明确地创建普通SQL模板,如上图所示,像这样:

Field<Integer> field = field("(1 + 2)", SQLDataType.INTEGER);Table<?> table = table("generate_series(1, 10)");Condition condition = condition("some_function() = 1");复制代码

这些表达式现在可以嵌入你的查询中,就像其他的一样:

ctx.select(field) .from(table) .where(condition) .fetch();复制代码

另外,在一些查询方法上也存在方便的重载,使之更加简单:

ctx.select(field("(1 + 2)", SQLDataType.INTEGER)) // Not on SELECT .from("generate_series(1, 10)") .where("some_function() = 1") .fetch();复制代码

请注意,select() 方法还没有这样的便利API,截至jOOQ 3.13

重要的免责声明:使用这些API,你将把自己暴露在通常的SQL注入风险中,在使用JDBC或JPQL时,从字符串组成的SQL也存在这种风险。千万不要连接纯SQL模板,也不要在这些字符串中使用用户输入。使用模板语言,并将所有的用户输入变成绑定变量。例子:

ctx.select(...) .from(...) .where("some_function() = ?", 1) // Bind variable .fetch(); ctx.select(...) .from(...) .where("some_function() = {0}", val(1)) // Templating .fetch(); 复制代码

如果你在jOOQ的大多数查询API上遇到字符串类型,那是用于纯SQL模板的。所有这些API都被注释为 @org.jooq.PlainSQL以供额外的文档使用,并通过静态检查器进行预处理,该检查器可用于默认禁止此类API的使用,以增加安全性。

3.名称(标识符)

但是在jOOQ的一些查询API上,字符串对于普通的SQL模板并不方便,而是用于名称和标识符。也就是说,所有的DDL语句在其API中都是这样使用字符串的。 你可以按以下方式明确地创建合格或不合格的标识符:

// Unqualified table identifierName table = name("t");// Qualified column identifierName field = name("t", "col");复制代码

然后,在你的DDL语句中使用这些标识符,例如,创建表:

ctx.createTable(table) .column(field, SQLDataType.INTEGER) .execute();复制代码

取决于上下文,限定是必要的或不需要的。在这种情况下,字段的限定是没有必要的。 为了方便起见,你也可以只使用字符串类型在 createTable(String)API。

ctx.createTable("t") .column("col", SQLDataType.INTEGER) .execute();复制代码

这些字符串将简单地被包裹在 DSL.name(String)

注意:在jOOQ中,所有的标识符都被默认为带引号(RenderQuotedNames.EXPLICIT_DEFAULT_QUOTED )。这有两个好处:

特殊字符,更重要的是,关键词冲突在开箱时就得到了正确的处理 引号可以防止SQL注入 在那些支持引号标识符的方言中,大小写敏感性得到了正确的处理

为这种便利付出的代价是,引号标识符可能会变成大小写敏感,而这是不希望的。为了解决这个问题,你可以使用你的设置关闭引号,例如,通过设置RenderQuotedNames.EXPLICIT_DEFAULT_UNQUOTED 。但要注意,如果你不先对标识符的名称进行消毒,这将使你再次面临SQL注入的风险。

4.关键词

在jOOQ中,关键词也是字符串。在极少数情况下,你可能想把你的关键词作为字符串表示在一个 org.jooq.Keyword类型中。主要的好处(从jOOQ 3.13开始)是一个一致的关键词风格。这方面没有方便的API,因为客户端代码很少使用这个功能。只有 DSL.keyword(String):

Keyword current = keyword("current");Keyword current = keyword("time");复制代码

你现在可以在纯SQL模板中使用关键字:

Field<Time> currentTime = field( "{0} {1}", SQLDataType.TIME, current, time);