这一版本历时多年,ORM 6.0 最终版终于发布!
本公告将讨论主要变更,并深入探讨为何做出某些选择。
我们还将通过一系列更专注于特定改进或新特性的文章来跟进。敬请期待!
APIs 和 SPIs
虽然 6.0 版本中有很多变化,但我们努力最小化对 API 的更改,以帮助减轻迁移成本。
请参阅 https://hibernate.com.cn/community/compatibility-policy/ 了解我们认为的 API 与 SPI 的区别。 |
仅使用 Jakarta Persistence API 的应用程序将在 Jakarta Persistence 部分的讨论中保持源兼容性。
使用 Hibernate API 的应用程序通常在字节码和源代码上保持兼容性,但需要移除已弃用的内容。还有一些一次性更改会破坏字节码和/或源代码兼容性;这些内容在 迁移指南 中有所说明。
值得注意的是,许多这些合约都通过类型参数得到了更好的定义。在之前的版本中,这些定义通常不一致,有时还定义得不好。
许多 SPI 合约已更改,以支持在此处以及 迁移指南 中讨论的许多主题。其中许多也将是后续文章的主题。
Jakarta Persistence
Java Persistence 已成为 Jakarta Persistence,这是 Java EE 整体迁移到 Jakarta 的一部分。各种法律要求迫使更改了 javax
命名空间 - 对于持久性而言,这意味着将包名以及属性和提示名称从 javax.persistence
更改为 jakarta.persistence
。
这显然是一个不幸且侵入性的变更,但我们无法控制。幸运的是,Jakarta 开发了一个转换器来帮助这些迁移。我们实际上使用了这个工具来迁移 Hibernate 的源代码。它效果还不错。
对于那些使用 Maven 的人来说,你很幸运(好吧,在实际上使用 Maven 的范围内)因为 Jakarta 本身提供了一个 Maven 插件来集成这个转换器。
对于那些使用 Gradle 的人来说,你可以使用我们开发的用于转换 Hibernate 源代码的任务。
还有一个命令行形式。有关详细信息,请参阅转换器文档。
按位置读取
几年前,大约在 5.4 时期,我们与 Red Hat 令人惊叹的性能团队合作,从 Hibernate ORM 中挤出更多的出色性能。
这项工作是我们改进 WildFly 性能更大努力的一部分。最终,Hibernate 中进一步改进的限制因素是我们的从 JDBC ResultSet
中按名称而不是按位置读取值的做法。对于所有的 JDBC 驱动程序,按名称读取都较慢。
很快就很明显,最小的更改是不够的,因此这项工作导致了许多变化。一个很好的类比是将基于 Map 的解决方案迁移到基于 List 的。这显然会对调用从接受一个 String
而不是一个 int
进行更改产生影响,以及在内部分配跟踪每个选定的值在 ResultSet
中的位置。还有可能不那么明显的影响,即更改那些调用者和消费者合同以跟踪位置。
这些更改在多个方面带来了改进
-
如前所述,按位置读取比按名称读取要快得多,这导致了性能改进。
-
从历史上看,Hibernate 生成的 SQL 选择查询具有定义良好的命名列别名的模式,这些别名随后用于访问特定的结果。我们都见过这些“丑陋”的别名。随着这些更改,选择子别名不再需要,从而使生成的 SQL 更易于阅读。
-
尽管我们在 5.x 中实现了一些对实体映射中所需连接的限制的改进(联合继承、二级表),但 6.0 提供了更好的机会。实际上,5.x 中对这一功能的支持是从 6.0 的工作中概念上回滚的。
-
(2) 和 (3) 结合起来,导致需要发送到服务器的 SQL 更小,这可能对网络通信产生影响。每一个比特都很重要。
这无疑是 6.0 初始阶段最大的推动力。
映射模型
映射模型是一个 SPI,因此并不是所有用户都能看到它。但这是一个主要的发展,影响了许多提供扩展的用户。
推动这一映射模型工作的主要动力是按位置读取,我们在开发它时有一些设计目标
-
支持属性的位置处理
-
使其面向对象
-
使其用户友好
可以通过RuntimeMetamodelsImplementor
访问此模型,它提供对两者的访问
-
Jakarta Persistence 模型:
JpaMetamodelImplementor
-
Hibernate 映射模型:
MappingMetamodelImplementor
HQL
Hibernate的前几个版本使用Antlr 2进行解析。6.0更新到Antlr 4,出于几个原因
-
Antlr 2不再受支持,并且已经多年不受支持
-
Antlr 4比Antlr 2快
-
Antlr 4语法更容易维护,而之前的Antlr 2语法定义不明确(很大程度上是Antlr 2本身的函数),难以维护。
Criteria
Hibernate的遗留Criteria API已经弃用多年,并在6.0中完全删除。现在仅通过Jakarta Persistence API及其扩展提供对Criteria查询的支持。
如语义查询模型中所述,Hibernate的SQM模型是Jakarta Persistence Criteria节点API的实现。这在与之前版本相比提供了显著更好的性能。
6.0还增加了一个与Criteria性能相关的新设置 - hibernate.criteria.copy_tree
。Jakarta Persistence规范要求对传递给EntityManager#createQuery
的Criteria树进行复制。这显然会有性能影响,但这是出于安全考虑。hibernate.criteria.copy_tree
允许Hibernate不复制树,从而提高性能。只需确保在调用#createQuery
之后不要修改树。
SQL作为AST
6.0在将查询建模为树方面全面投入。我们上面讨论了这如何适用于HQL和Criteria查询,但我们现在也以树的形式建模SQL查询。
这有很多好处,但主要好处是直接涉及Dialect。树作为将AST转换为JDBC调用的API,允许Dialect在此过程中发挥更强大的作用。
Dialect初始化
在之前版本中,Dialect基本上是关于使用数据库的静态细节。这意味着Dialect实现不能结合特定版本偏差,这也是为什么Hibernate有这么多版本特定的子类。
6.0改变了Dialect创建的方式,使其能够根据使用的数据库/驱动程序的版本初始化自己。
@Incubating
6.0 版本还引入了一个新的 @Incubating
注解,目的是通知用户,某个特定合约在未来可能会发生变化。这些通常是新合约,我们可能需要根据额外的用例或对现有用例的澄清来更改它们。
把它想象成一种“自行承担风险”的警告。显然,我们会努力不更改这些合约,但这给了我们在需要时更改它们的灵活性,并向用户传达这种可能性。
有时设置被认为是孵化中的。这些在相应的 org.hibernate.cfg.AvailableSettings
字段上用 @Incubating
标记,并且还使用 org.hibernate.orm.incubating
类别进行日志记录。
我们还生成了一个文档 报告。