在这篇文章中,我想向大家介绍 Lukas Eder,Java冠军,SQL爱好者,数据访问框架开发者。

嗨,卢卡斯。你想自我介绍一下吗?
嗨,弗拉德,我是 @lukaseder,Data Geekery公司的创始人兼首席执行官,该公司是 jOOQ 的幕后公司。我是一位Java冠军和Oracle ACE,我肯定会很快从其他供应商那里获得所有其他酷炫的徽章。我拥有数百万Stack Overflow声誉、Reddit karma和其他重要的互联网积分,并且最近在LinkedIn上得到了认可,不仅是因为XML,还因为微软Excel响应式编程 - 这是唯一比SQL更强大的工具。
除了这些引人注目的成就之外,我主要在jOOQ及其客户咨询服务的Java、SQL和PL/SQL周围进行编码和调优。我还提供公开和内部 SQL培训,并且通常在努力让使用SQL的Java开发者生活更轻松。
你可以在会议上见到我,我在那里向那些被企业软件架构师强迫在非SQL(第三代编程语言)中编写业务逻辑的可怜的灵魂(或那些自己选择这样做的不寻常的开发者)讲述SQL的奇妙之处。来看看我的演讲,你将看到光明!
我一直想知道jOOQ是如何诞生的。你能告诉我们这一切是如何开始的吗?
jOOQ的灵感起源于19世纪初,当时Ada Lovelace实际上发明了编程。她肯定能预见到这一点。一旦算法成为现实,世界就准备好了SQL,以及jOOQ。然而,在她令人印象深刻的作品之后,许多弯路被走,直到150年后SQL的发明,以及大约到2009年,当时才清楚SQL必须成为Java的一部分。因此:jOOQ。
当只关注2009年的历史时,jOOQ是“意外”出现的。当时,本质上,每个人都在创建本地的查询构建器来抽象掉拼接字符串“A = 1”和“B = 2”,并用“AND”连接它们,偶尔也用“OR”。全球在该领域投入的努力只能用地质时间尺度(“人纪”)来衡量。这些努力都白费了,因为即使在同一公司内,几个团队也在重复同样的工作。
大多数这些内部工具只能大致处理SELECT .. FROM .. WHERE。JOIN支持很少(甚至不理解),如果你添加GROUP BY,就会出现 Cambrian 爆炸般的错误、补丁和进一步的人纪维护工作。
所有这些都意味着必须有一个行业需求,一个市场,需要一种每个人都可以使用的工具。一个工具,确保构建SQL字符串的问题将被永久解决。当时,至少有10个概念验证风格的开源库,也许还有一个叫做QueryDSL的工具更进一步。但它们都没有完全投入SQL语言。再次,大多数都处理SELECT .. FROM .. WHERE,然后基本就停在那了。
jOOQ 必须被制作出来,并永久存在。
当谈到持久化和检索数据时,jOOQ采用了什么方法?它与Hibernate使用的基于事务的延迟写入方法相比如何?
jOOQ“只是”类型安全的JDBC/SQL,即它是一个API,允许用户以编译时类型检查的SQL表达式树的形式编写SQL,这些表达式树看起来非常像实际的SQL。所以,问题不是持久化和检索数据的方法,而是编写查询的方法。
你可以将jOOQ与JPA的Criteria Query API进行比较,后者“只是”类型安全的JPA/JPQL - 尽管我必须说Criteria Query可能执行得更好。编写内部领域特定语言(DSL)真的很难。在API维护和保持向后兼容性方面的含义非常棘手。我认为Criteria Query被过早地添加到JPA规范中。现在我们有了它,它永远无法真正改变,只能,或许,被取代。
现在,如果你想比较编写查询的方法(SQL、JDBC、jOOQ、JPA原生查询)与“事务后延迟写入”方法(JPA、Hibernate、其他ORM),讨论就会变得更加复杂,并且不仅与工具相关,还与架构相关。
简而言之,SQL方法更注重批量数据处理(读写都一样),而JPA方法更注重CRUD。SQL是无状态的/无会话的/无副作用的,而JPA是有状态的/“会话的”/命令式的。SQL在数据库中运行基于集合的计算逻辑,提供现代SQL优化器的复杂性,而JPA在客户端运行基于记录的计算逻辑,提供Java库和客户端处理的广泛可能性。
所以,很明显,这两者代表的不只是不同的技术,还有不同的范式和思维模式。
然而,这仍然无法解释为什么在特定情况下,每种方法都可能成为首选。这是一个非常棘手的问题。我个人只与那些SQL方法明显更有优势的系统工作过(大型数据集、数千张表、每个查询需要数十个JOIN、数千个并发查询、数千个存储过程、很少的并发写入、混合OLTP和OLAP工作负载) - 但我知道很多人和他们的系统,对于他们使用的复杂事务模式,纯SQL会是有害的,而JPA真正闪耀。
理想情况下,我们可以结合两个世界的优点:SQL和JPA——或者jOOQ和Hibernate,这些都是具体的实现。因为最终,没有一个解决方案适合所有情况,以一个简单的例子来说,在一个OLTP/CRUD(JPA)应用中,你将会有报告和分析(SQL)。
当然,我以前也在博客中讨论过这个话题。
如何轻松集成jOOQ和Hibernate,以及结合这两个框架的主要优势是什么?
有几种不同的集成方式。
集成查询API
从API的角度来看,这非常简单。从jOOQ 3.10开始,你可以直接从jOOQ查询中提取任何SQL字符串和绑定变量集,将查询发送到Hibernate/JPA原生查询API,然后让Hibernate根据JPA标准进行映射。这可以与以下操作一起使用
-
将普通原生查询映射到
Object[]
记录表示 -
将“增强”的原生查询映射到
@SqlResultSetMapping
规范 -
将普通原生查询映射到实体
特别是后者可以非常强大。有时,你确实想要得到管理实体作为结果,但你无法在JPQL查询/标准查询/命名实体图中表达查询的复杂性。简单的例子包括使用并集、公用表表达式、派生表、横向连接等,这些都是JPQL不支持很好的功能。
在这种情况下,SQL表现出色,从性能和维护性的角度来看,它几乎总是比将所有数据加载到内存中并在Java中实现逻辑更好的选择。你只需要确保选择你想要物化的实体图所需的所有列,可能需要使用一些Hibernate特定的ResultTransformer
(看看谁写了这个话题 ;)),然后你就完成了。
未来的jOOQ版本,希望是3.11(对于工作组来说),将通过直接将jOOQ SPI绑定到EntityManager
来进一步简化集成。这将消除从jOOQ查询中提取SQL字符串和绑定变量的需求,并允许直接使用jOOQ API在EntityManager
上执行查询。我非常期待这个功能,它使得使用两个世界的最佳方案变得非常简单。
集成代码生成
另一个酷的集成点是基于JPA注解实体的jOOQ代码生成,Hibernate在幕后使用。许多项目已经使用Hibernate,并希望运行几个报告或实体查询使用SQL,因此也使用jOOQ。他们现在可以使用Hibernate逆向工程JPA注解实体,从它们生成一个内存中的H2数据库,然后jOOQ可以读取这个H2数据库以生成jOOQ代码。
尽管我个人更喜欢使用DDL,但许多项目将他们的JPA注解实体视为他们的主要模式信息来源,因此这种方法非常适合他们。
在JDBC级别集成
一个不太为人所知的集成点是,jOOQ通过至少两个基于JDBC的低级SPI公开自己
-
解析器API
-
模拟API
在两种情况下,jOOQ都可以代理一个JDBC连接并执行诸如
-
解析发送到 jOOQ 的 SQL 字符串,并将 SQL 表达式树转换为其他形式,例如通过应用 VisitListener。这可以用来实现 客户端行级安全,或者复杂的租户隔离,或其他功能。此外,解析后的 SQL 字符串可以转换为其他 SQL 方言(尽管在已经具有方言无关性的 Hibernate 中这并不特别有用)。未来的 jOOQ 版本将能够对任意 SQL 字符串应用自定义格式化,因此这可以作为 Hibernate 生成的 SQL 的格式化工具,用于日志记录。
-
SQL 语句可以通过单个 SPI 进行模拟,在某些情况下返回“假”结果。在简单的设置中,这可以非常强大,用于拦截查询进行测试或其他目的。
同样,这些功能不暴露 jOOQ 给客户端,而是将 jOOQ 隐藏在 JDBC 之下,这样它们可以直接与 JDBC 一起工作,或者与 Hibernate 一起工作。
对于许多 Java 开发者来说,SQL 的知识水平相当基础。您会推荐 Java 开发者学习哪些出色的 SQL 功能呢?
确实如此,非常不幸。我建议这样做
-
首先,不要害怕 SQL。SQL 是一种非常简单的函数式编程语言,它的语法有些古怪、晦涩。你喊得越响,它运行得越快,对吧?(这个笑话归功于 Aleksey Shipilëv)。但是,为了真正理解 SQL(无论是基本的还是复杂的 SQL),我认为记住它的起源很重要 关系代数。如果这一点得到正确理解,特别是大多数操作只是基本集合运算(如集合并和笛卡尔积)的语法糖,那么语言会更有意义,而且它真正的强大之处也会变得清晰。
-
然后,我建议阅读这篇 关于 SQL 的真正有趣的博客 ;) 并关注一些更高级的功能。其中最重要的是公共表表达式(CTE)和窗口函数。CTE 非常容易理解,在编写复杂查询时会立即增加价值。窗口函数稍微有点棘手,但我可以说在日常工作中也非常有益。一旦理解了这些,还有很多其他功能值得探索。在我的文章 “10SQL Tricks That You Didn’t Think Were Possible” 中展示了复杂示例,但还有许多其他简单功能可以每天使用。我将在未来的博客中介绍更多内容,我还在写一本书(这比预期的要花更长的时间,因为有两个孩子…),当然,这些主题也包含在我的 SQL 培训 中。
我们始终重视来自社区的反馈,所以您可以告诉我们您希望我们添加哪些功能,以便其他数据访问框架更容易与 JPA 或 Hibernate 集成?
我知道我们已经讨论了现有的 ResultTransformer
SPI 将在 Hibernate 6.0 中得到改进的事实。这可能是其他数据访问框架(如 jOOQ)中最有趣的 SPI 之一。我希望新版本将在 JPA 中标准化,并允许在平面结果集和实体图之间进行真正的自定义转换。在我看来,我一直在想为什么像 Hibernate 这样流行的 O/R 映射工具会在单个工具中做所有的事情,主要是因为
-
建模部分
-
映射部分
-
查询部分
-
会话/缓存管理部分
如果这些部分可以被拆分成不同的、独立的JPA/Hibernate模块,整个工具链将更加强大。例如,如果有一个只关注如何将扁平数据映射到注解实体图(但不会担心管理这些实体或获取它们,因为那将属于会话/缓存管理部分或查询部分)的Hibernate映射库,那将会非常有用。
感谢Lukas抽出时间。能在这里见到您非常荣幸。要联系Lukas,您可以在Twitter上关注他。