Hibernate和Spring Data JPA有什么区别?

337

Hibernate和Spring Data JPA之间的主要区别是什么?

在什么情况下不应该使用Hibernate或Spring Data JPA?

此外,何时Spring JDBC模板可能比Hibernate和Spring Data JPA表现更好?


13
@NeilStockton询问两种技术之间的比较,并不是要求意见。 - Philip Rego
6个回答

449
Hibernate是JPA的实现,而Spring Data JPA是JPA数据访问抽象层。Spring Data JPA不能没有JPA提供程序。
Spring Data提供了DDD Repository模式或传统GenericDao自定义实现的解决方案。它还可以通过方法名称约定代表您生成JPA查询。
使用Spring Data,您可以使用Hibernate、EclipseLink或任何其他JPA提供程序。使用Spring或Java EE的一个非常有趣的好处是,您可以使用@Transactional注释声明性地控制事务边界。
Spring JDBC更加轻量级,适用于本机查询,如果您只打算仅使用JDBC,则最好使用Spring JDBC来处理JDBC的冗长代码。
因此,Hibernate和Spring Data是互补而不是竞争对手。

81
这是否意味着Spring Data JPA不能独立存在?也就是说,在其内部,它使用JPA提供程序之一(如Hibernate、Eclipselink或任何其他JPA提供程序)? - CuriousMind
我的意思是,如果我只使用Hibernate,那么Hibernate级别的配置就很少,如果我使用Spring Data JPA,那看起来比Hibernate容易得多。从这个意义上说,我问了你那个问题。 - Asif Mushtaq
1
更准确地说,到目前为止一切都运行良好,您只需要理解顶层即Spring Data JPA。除了第一个例外情况,您可能还需要了解较低级别,即Hibernate、JDBC和数据库。 - Marmite Bomber
14
不,Spring Data不能独立存在(工作)。它默认使用Hibernate实现,您可以在“spring-data-jpa”中的子依赖项中注意到“hibernate-core”。 - CᴴᴀZ
一般来说,实现与API的分离是一个很好的设计。在这种情况下,Spring Data实现了存储库作为API的想法。这个API完全基于存储库模式,并且不依赖于其他任何东西。Hibernate、Eclipse Link或其他库为Spring Data API提供了实现。从开发者的角度来看:编译阶段需要Spring Data,运行时阶段需要Hibernate。 - Chi Cuong Le

222

这里有三个不同的东西:

  1. JPA:Java持久化API,提供了将java对象持久化、读取、管理到关系数据库中的规范。
  2. Hibernate:有许多实现JPA的提供者,Hibernate是其中之一。所以我们还有其他提供者。但如果在Spring中使用JPA,它允许您在将来切换到不同的提供者。
  3. Spring Data JPA:这是Spring提供的另一个在JPA之上的层,可使您的工作更轻松。

因此,让我们了解一下spring data jpa和spring + hibernate是如何工作的-


Spring Data JPA:

假设您正在使用Spring + Hibernate开发应用程序。现在您需要拥有Dao接口和实现,您将使用Hibernate的SessionFactory编写CRUD操作。假设您正在为Employee类编写Dao类,明天在您的应用程序中,您可能需要为任何其他实体编写类似的CRUD操作。因此,我们可以看到很多样板代码。

现在,Spring Data JPA允许我们通过扩展其repositories(CRUDRepository、JPARepository)来定义Dao接口,因此它会在运行时为您提供Dao实现。您不再需要编写Dao实现。这就是Spring Data JPA如何使您的工作更轻松。


12
Spring Data JPA 的底层实现是什么?是 Hibernate 吗?因为当我使用 PagingAndSortingRepository 时,控制台会显示 Hibernate 日志。 - Vikki
21
Spring Data JPA默认使用Hibernate实现。如果查看spring-boot-starter-data-jpa的传递依赖项,您会发现其中包含了hibernate-core。 - IamVickyAV

43

我不同意SpringJPA让生活变得容易。是的,它提供了一些类,可以快速创建一些简单的DAO,但实际上,这就是你所能做的。 如果你想做比findById()或save更多的事情,你必须经历痛苦:

  • org.springframework.data.repository类中没有EntityManager访问(这是基本的JPA类!)
  • 自己的事务管理(不允许使用hibernate事务)
  • 配置多个数据源时存在巨大问题
  • 没有数据源池(必须使用第三方库HikariCP)

为什么自己的事务管理是一个缺点?由于Java 1.8允许接口中的默认方法,基于Spring注解的事务处理非常简单实用。

不幸的是,SpringJPA基于反射,有时需要在注释中指定方法名或实体包名。这就是为什么任何重构都会造成严重崩溃。 遗憾的是,@Transactional仅适用于主数据源 :( 因此,如果您有多个数据源,请记住 - 事务只适用于主数据源 :)

Hibernate和Spring Data JPA之间的主要区别是什么?

Hibernate兼容JPA,SpringJPA兼容Spring。你的HibernateJPA DAO可以与JavaEE或Hibernate Standalone一起使用,而SpringJPA可以在Spring中使用 - 例如SpringBoot。

什么时候不应该使用Hibernate或Spring Data JPA?还有什么情况下Spring JDBC模板可能比Hibernate/Spring Data JPA表现更好?
仅在需要使用大量连接或需要使用具有多个数据源连接的Spring时才使用Spring JDBC。通常,避免在连接方面使用JPA。
但是我的一般建议是使用全新的解决方案 - Daobab(http://www.daobab.io)。 Daobab是我的Java和任何JPA引擎集成器,我相信它将在您的任务中提供很大帮助 :)

3
Daobab,真的吗?如果你不喜欢jpql缺乏类型安全性(我不喜欢),JPA有一个类型安全的criteria API...标准JPA比那个糟糕的替代品更好。 - ymajoros
当你使用Spring Data JPA时,没有理由需要访问EntityManager,所以这不是一个问题。Spring还可以很容易地声明式地管理事务,不需要自己操心Hibernate的事务。关于多个数据源的“巨大问题”:如果你知道你在做什么,这并不复杂。而且@Transactional并不只适用于主数据源。关于没有数据源池化的说法:我不知道你为什么这样认为,但这简直是不真实的。 - Jesper
@Transactional害死了我的上一个项目。我正在阅读这篇文章,因为我必须重新学习关于在Spring Boot项目中使用ORM的内容,以便理解@Transactional的工作原理。我不能再多说了,因为我真的不理解@Transactional。 - undefined

18

Spring Data是建立在JPA之上的一个方便的库,它抽象了很多东西,并将Spring魔法(喜欢或不喜欢)带入了持久化存储访问中。它主要用于处理关系数据库。简而言之,它允许您声明具有像findByNameOrderByAge(String name);这样的方法的接口,这些方法将在运行时解析并转换为适当的JPA查询。

它位于JPA之上,使得其使用对以下人员诱惑:

  1. 不懂SQL或掌握得不好的新手开发人员。这是灾难的开始,但如果项目比较简单,他们可以通过这种方式摆脱困境。

  2. 知道自己在做什么并想要快速启动事情的有经验的工程师。这可能是一种可行的策略(但请继续阅读)。

从我的Spring Data经验来看,它的“魔法”太多了(这同样适用于一般的Spring)。我在一个项目中大量使用它,最终遇到了几个角落情况,我无法摆脱库的限制,最终得出了丑陋的解决方案。后来我看了其他用户的投诉,并意识到这些问题对于Spring Data来说是典型的。例如,请查看此问题,它导致了数小时的调查/咒骂:

 public TourAccommodationRate createTourAccommodationRate(
        @RequestBody TourAccommodationRate tourAccommodationRate
    ) {
        if (tourAccommodationRate.getId() != null) {
            throw new BadRequestException("id MUST NOT be specified in a body during entry creation");
        }

        // This is an ugly hack required for the Room slim model to work. The problem stems from the fact that
        // when we send a child entity having the many-to-many (M:N) relation to the containing entity, its
        // information is not fetched. As a result, we get NPEs when trying to access all but its Id in the
        // code creating the corresponding slim model. By detaching the entity from the persistence context we
        // force the ORM to re-fetch it from the database instead of taking it from the cache

        tourAccommodationRateRepository.save(tourAccommodationRate);
        entityManager.detach(tourAccommodationRate);
        return tourAccommodationRateRepository.findOne(tourAccommodationRate.getId());
    }

我最终降低了层次,开始使用JDBI - 这是一个不需要编写样板代码就足够"神奇"的好库。使用它,你可以完全控制SQL查询,几乎不必与库进行斗争。


2
这是一个很好的答案,但如果您能列出角落情况并进一步详细说明,那将非常有帮助。它将成为一个伟大的答案。谢谢。 - John Eipe
2
嗯,由于我已经有一段时间没有使用Spring Data了,所以要回忆起这些并不容易 - 我需要查看旧代码并添加更多注释。然而,我脑海中的一个烦恼之一是,在JPA中,对象经常需要相互引用(例如,用于级联操作)。这会导致堆栈溢出错误(由于循环引用),当Spring尝试序列化它们时,会强制你进行丑陋的调整/解决方法。虽然这个问题与Spring Data无关,但它是一个JPA问题。然而,由于JPA是Spring Data的基础,你可以“免费”得到它。 - raiks
1
编辑了帖子并添加了一个例子。 - raiks

2

如果您更喜欢简单和更多的SQL查询控制,则建议选择Spring Data / Spring JDBC。

JPA有很多学习曲线,有时很难调试问题。另一方面,虽然您可以完全控制SQL,但优化查询并提高性能变得更加容易。您可以轻松地与DBA或对数据库有更好了解的人分享SQL。

“Original Answer”翻译成中文为“最初的回答”。


0
Hibernate是“JPA”的实现,它是Java对象在数据库中的规范。
我建议使用JPA,因为你可以在不同的ORM之间切换。
当你使用JDBC时,你需要使用SQL查询,所以如果你精通SQL,那就选择JDBC吧。

什么是w.r.t.? - darw
1
关于 - Thoopalliamar
1
我自己有时也会使用WRT,但你在这里的使用没有意义。 - Shane

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接