SQL 方言如何在 hibernate 和 JOOQ 等框架内部实际工作

Posted

技术标签:

【中文标题】SQL 方言如何在 hibernate 和 JOOQ 等框架内部实际工作【英文标题】:How do SQL dialects actually work internally in frameworks like hibernate and JOOQ 【发布时间】:2019-09-18 10:32:41 【问题描述】:

正如我们所看到的,在您获得数据源之后。我们需要根据我们使用的数据库来配置 SQL 方言。在我们选择了一种特定的方言之后,如何使用它来进行特定于 DB 的 SQL 查询。像 hibernate 和 JOOQ 这样的框架是否会根据所选方言在字符串中构造 SQL 查询?如果是这样,哪一种是在我们自己的框架中支持这一点的最佳方式?

【问题讨论】:

我非常怀疑是否有人能告诉您这些 ORM 解决方案的确切实现,除非您以某种方式掌握了这些 ORM 解决方案的开源版本。对于 EF,我知道它实际上只是创建准备好的语句(基本上以字符串形式),具体取决于所使用的配置和连接,但实际转换是由另一个库(EF db 提供程序)完成的。 @DevilSuichiro:解开你的疑惑,我来回答了。 【参考方案1】:

像 hibernate 和 JOOQ 这样的框架是否会根据所选方言在字符串中构造 SQL 查询

是的。在 jOOQ 中,有一个内部 StringBuilder 从您的表达式树中收集 SQL 片段,这些片段是专门为您的目标 SQL 方言生成的。你可以在这个网站上看到它是如何工作的:https://www.jooq.org/translate。例如,尝试翻译此输入:SELECT * FROM t LIMIT 1(可能对应于您的 jOOQ API 用法ctx.selectFrom(T).limit(1)。它翻译为:

-- Oracle 12c and more
SELECT * FROM t FETCH NEXT 1 ROWS ONLY

-- Oracle 11g and less
SELECT *
FROM (
  SELECT x.*, rownum rn
  FROM (SELECT * FROM t) x
  WHERE rownum <= 1
)
WHERE rn > 0

如果是这样,在我们自己的框架中支持这一点的最佳方式是什么?

你需要:

    SQL 查询的表达式树表示。 (可选)您可以解析字符串来构建此表达式树,如 jOOQ's parser,如果您想支持实际 SQL,或者您可以拥有自己的语言抽象,如 Hibernate 对 HQL / JPQL 所做的那样 使用类似访问者的方式遍历该表达式树以收集 SQL 字符串并绑定变量。

但是!

当您拥有 jOOQ 等现成产品或在较小程度上可以做到这一点的 Hibernate 时,请勿构建您自己的产品。构建这样一个通用的 SQL 抽象真的很困难,除非你想真正销售这样的产品(你可能没有给出你的问题),否则花时间来构建这个产品根本不值得。

上述LIMIT 仿真是jOOQ 中更简单的示例之一。 Here's a lot more to help you decide against rolling your own,这个答案仍然只是触及 jOOQ 在幕后所做的事情的表面。

【讨论】:

我同意您的观点,即为现有框架已经提供的相同内容编写另一个框架将浪费时间。问这个问题的动机是了解众所周知的框架内部发生了什么,是否有多种方法可以解决这个方言问题。如果是,我应该为我正在尝试构建的应用程序考虑哪种方式。谢谢,直到今天我才意识到包装特定于数据库的 SQL 查询时遇到的问题数量。 @LukasEder @AbhayJatinDoshi:是的,好吧,就 SQL 语法支持或 JDBC API 支持而言,有无穷无尽的特殊情况。这甚至没有涉及必须为特定 RDBMS 手动重写慢查询的主题,因为 RDBMS 的优化器不是很好:)

以上是关于SQL 方言如何在 hibernate 和 JOOQ 等框架内部实际工作的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate SQL方言 (hibernate.dialect) Spring配置文件applicationContext.xml

Hibernate不同数据库的连接及SQL方言

hibernateHibernate SQL 方言(hibernate.dialect)

为啥需要配置数据源的 SQL 方言?

[转]Hibernate不能自动建表解决办法及Hibernate不同数据库的连接及SQL方言

5 -- Hibernate的基本用法 --4 4 数据库方言