最近参加了一个Spring相关活动,在活动中,与Spring生态系统的关键人物奥利弗·德罗特博姆(Oliver Drotbohm)直接合作的专家们讨论了一个有趣的趋势:许多团队,包括博通(Broadcom)的团队,正在放弃Java持久化API(JPA)(Hibernate),转而重新使用Java数据库连接(JDBC)。
这一转变在各个行业中越来越受关注,尤其是在高性能应用程序领域。
多年来,JPA一直是Spring应用程序中进行数据库交互的首选抽象方式,它提供了一种简化的处理持久化的方法。然而,其带来的额外开销、性能瓶颈以及缺乏细粒度的控制正促使开发人员重新考虑是否继续使用它。
让我们来探究一下这种转变发生的原因。
转变背后的核心原因
1. JPA(Hibernate)中的性能瓶颈
JPA在SQL之上引入了一个抽象层,这可能会导致严重的性能问题:
- • 延迟加载和N+1查询问题:获取相关实体时常常会导致多个不必要的查询,这会显著影响性能。
- • 脏数据检查开销:Hibernate会在会话中跟踪实体的变化,当处理大量记录时,这可能会导致性能下降。
- • 查询优化限制:对象关系映射(ORM)生成的查询对于复杂的业务逻辑来说往往不是最优的。
对于处理大量数据集的应用程序来说,这些低效率使得JPA不太适用,促使团队选择JDBC,因为使用JDBC他们可以直接控制查询的执行。
2. JDBC提供对查询的完全控制
使用JPA时,开发人员依赖于Hibernate生成的SQL,而这些SQL并不总是经过优化的。相比之下,JDBC允许:
- • 直接执行自定义SQL查询
- • 更好地利用索引以及对查询性能进行调优
- • 实现高效的分页策略
对于数据密集型应用程序,手动编写的SQL查询通常比JPA生成的查询性能更好,从而带来更高的效率和可维护性。
3. 减少内存开销
JPA维护着一个持久化上下文,它会跟踪实体状态并在内存中缓存数据。虽然这有助于自动跟踪变化,但它也会:
- • 增加堆内存消耗
- • 导致不必要的实体状态跟踪,即使在不需要的时候也是如此
- • 在大规模数据处理中引发内存溢出错误(OutOfMemoryErrors)
JDBC通过仅返回所需数据消除了这种开销,使其成为高性能应用程序的更好选择。
4. Hibernate的可扩展性限制
随着应用程序的扩展,JPA的局限性变得更加明显:
- • 会话管理开销:每个事务都持有一个跟踪实体变化的会话,这会消耗更多资源。
- • 复杂关系处理:获取相关实体可能会生成效率低下的SQL,从而减慢响应时间。
- • 不必要的自动刷新:Hibernate可能会在事务中间自动刷新更改,从而导致不可预测的行为。
JDBC不维护会话级别的缓存,避免了这些可扩展性瓶颈。
5. 更透明的事务处理和调试
JPA的事务跨越多个层,这使得调试和回滚处理变得困难。而JDBC则提供了:
- • 对提交和回滚的明确控制
- • 更轻松的调试,因为开发人员可以控制确切的SQL执行流程
- • 事务行为的可预测性
6. 更快的应用程序启动时间
Hibernate在应用程序启动期间需要进行实体扫描、元数据初始化和缓存,这会增加启动时间。在微服务架构中,快速启动至关重要,而JDBC通过消除不必要的ORM开销具有一定优势。
Spring Boot 3和Project Loom的作用
随着Spring Boot 3和Project Loom(Java中的虚拟线程)的出现,JDBC可能会变得更加重要:
- • 虚拟线程减少了阻塞数据库调用的影响,使得直接的JDBC访问更具可扩展性。
- • JDBC允许开发人员在没有ORM限制的情况下对数据库交互进行微调。
因此,各个团队正在重新评估他们的数据库访问策略,许多团队因为JDBC的简单性、效率和可预测性而选择它。
这是否意味着JPA已经过时了呢?
不一定。JPA对于以下这些应用程序仍然有用:
- • 快速开发比精细调优的性能更重要的情况。
- • 领域模型与关系数据结构紧密映射的情况。
- • 数据库交互主要是增删改查(CRUD)操作,且复杂查询较少的情况。
然而,在需要高吞吐量、复杂SQL以及最优资源利用的应用程序中,JDBC正成为首选。行业的共识是,对于性能关键型应用程序使用JDBC,而对于更简单的用例则保留JPA。
总结
从JPA转向JDBC不仅仅是一个短暂的趋势——这是对高效、可扩展和高性能应用程序日益增长的需求的回应。
随着越来越多的团队认识到JPA和Hibernate的局限性,他们正在转向JDBC,以便更好地控制数据库交互。
如果你正在处理一个处理大量数据集或需要优化SQL查询的应用程序,也许是时候重新思考你的对象关系映射(ORM)策略了!!!
没有回复内容