CrudRepository findOne() 和 JpaRepository getOne() 的区别
Difference between CrudRepository findOne() and JpaRepository getOne()
我读到 getOne()
是延迟加载的,findOne()
会立即获取整个实体。我检查了调试日志,甚至在我的 sql 服务器上启用了监视以查看执行了哪些语句,我发现 getOne()
和 findOne()
都生成并执行了相同的查询。但是,当我使用 getOne()
时,值最初为空(当然除了 id)。
那么谁能告诉我,如果这两种方法对数据库执行相同的查询,为什么我应该使用其中一种呢?我基本上是在寻找一种方法来获取实体而不获取其所有 children/attributes.
编辑 1:
道代码:
@Repository
public interface FlightDao extends JpaRepository<Flight, Long> {
}
Debugging log findOne() vs getOne()
编辑2:
多亏了 Chlebik,我才能够确定问题所在。正如 Chlebik 所述,如果您尝试访问 getOne()
获取的实体的任何 属性,将执行完整查询。在我的例子中,我在调试时检查行为,一次移动一行,我完全忘记了在调试时 IDE 试图访问对象属性以进行调试(或者至少这是我认为正在发生的事情) ,因此调试会触发完整的查询执行。我停止调试然后检查日志,一切似乎都正常。
getOne()
vs findOne()
(此日志取自 MySQL general_log
而不是休眠。
这只是一个猜测,但在 'pure JPA' 中有一个名为 getReference 的 EntityManager 方法。它旨在检索其中只有 ID 的实体。它的用途主要是指示存在引用而不需要检索整个实体。也许代码会告诉更多:
// em is EntityManager
Department dept = em.getReference(Department.class, 30); // Gets only entity with ID property, rest is null
Employee emp = new Employee();
emp.setId(53);
emp.setName("Peter");
emp.setDepartment(dept);
dept.getEmployees().add(emp);
em.persist(emp);
我假设 getOne 具有相同的目的。为什么生成的查询和你问的一样?好吧,JPA 圣经中的 AFAIR - Mike Keith 和 Merrick Schincariol 的 Pro JPA2 - 几乎每个段落都包含类似 'the behaviour depends on the vendor' 的内容。
编辑:
我已经设置了自己的设置。最后我得出结论,如果您以任何方式干扰使用 getOne 获取的实体(甚至使用 entity.getId()),它会导致 SQL 被执行。尽管如果您仅使用它来创建代理(例如,对于上面代码中所示的关系指示器),什么也不会发生,也不会执行额外的 SQL。所以我假设在你的服务中 class 你对这个实体做了一些事情(使用 getter,记录一些东西),这就是为什么这两种方法的输出看起来一样。
ChlebikGitHub with example code
SO helpful question #1
SO helpful question #2
假设您要按 ID 删除 Entity
。在 SQL
中,您可以执行这样的查询:
"delete form TABLE_NAME where id = ?".
并且在 Hibernate
中,首先您必须获取 Entity
的托管实例,然后将其传递给 EntityManager.remove
方法。
Entity a = em.find(Entity.class, id);
em.remove(a);
但是这样,您必须在删除之前从数据库中获取要删除的 Entity
。真的有必要吗?
方法 EntityManager.getReference
returns 一个 Hibernate
代理,无需查询数据库和设置实体的属性。除非您尝试自己获取返回代理的属性。
方法JpaRepository.getOne
使用EntityManager.getReference
方法而不是EntityManager.find
方法。因此,每当您需要一个托管对象但实际上不需要为此查询数据库时,最好使用 JpaRepostory.getOne
方法来消除不必要的查询。
如果找不到特定 ID 的 table 数据,findOne 将 return 为 null,而 getOne 将抛出 javax.persistence.EntityNotFoundException。
两者各有利弊。请看下面的例子:
- 如果找不到数据对您来说不是失败案例(例如,您只是
验证数据是否被删除,成功将是数据
null),你可以使用 findOne.
- 另一种情况,你可以使用getOne。
如果您知道结果,可以根据您的要求进行更新。
我读到 getOne()
是延迟加载的,findOne()
会立即获取整个实体。我检查了调试日志,甚至在我的 sql 服务器上启用了监视以查看执行了哪些语句,我发现 getOne()
和 findOne()
都生成并执行了相同的查询。但是,当我使用 getOne()
时,值最初为空(当然除了 id)。
那么谁能告诉我,如果这两种方法对数据库执行相同的查询,为什么我应该使用其中一种呢?我基本上是在寻找一种方法来获取实体而不获取其所有 children/attributes.
编辑 1:
道代码:
@Repository
public interface FlightDao extends JpaRepository<Flight, Long> {
}
Debugging log findOne() vs getOne()
编辑2:
多亏了 Chlebik,我才能够确定问题所在。正如 Chlebik 所述,如果您尝试访问 getOne()
获取的实体的任何 属性,将执行完整查询。在我的例子中,我在调试时检查行为,一次移动一行,我完全忘记了在调试时 IDE 试图访问对象属性以进行调试(或者至少这是我认为正在发生的事情) ,因此调试会触发完整的查询执行。我停止调试然后检查日志,一切似乎都正常。
getOne()
vs findOne()
(此日志取自 MySQL general_log
而不是休眠。
这只是一个猜测,但在 'pure JPA' 中有一个名为 getReference 的 EntityManager 方法。它旨在检索其中只有 ID 的实体。它的用途主要是指示存在引用而不需要检索整个实体。也许代码会告诉更多:
// em is EntityManager
Department dept = em.getReference(Department.class, 30); // Gets only entity with ID property, rest is null
Employee emp = new Employee();
emp.setId(53);
emp.setName("Peter");
emp.setDepartment(dept);
dept.getEmployees().add(emp);
em.persist(emp);
我假设 getOne 具有相同的目的。为什么生成的查询和你问的一样?好吧,JPA 圣经中的 AFAIR - Mike Keith 和 Merrick Schincariol 的 Pro JPA2 - 几乎每个段落都包含类似 'the behaviour depends on the vendor' 的内容。
编辑:
我已经设置了自己的设置。最后我得出结论,如果您以任何方式干扰使用 getOne 获取的实体(甚至使用 entity.getId()),它会导致 SQL 被执行。尽管如果您仅使用它来创建代理(例如,对于上面代码中所示的关系指示器),什么也不会发生,也不会执行额外的 SQL。所以我假设在你的服务中 class 你对这个实体做了一些事情(使用 getter,记录一些东西),这就是为什么这两种方法的输出看起来一样。
ChlebikGitHub with example code
SO helpful question #1
SO helpful question #2
假设您要按 ID 删除 Entity
。在 SQL
中,您可以执行这样的查询:
"delete form TABLE_NAME where id = ?".
并且在 Hibernate
中,首先您必须获取 Entity
的托管实例,然后将其传递给 EntityManager.remove
方法。
Entity a = em.find(Entity.class, id);
em.remove(a);
但是这样,您必须在删除之前从数据库中获取要删除的 Entity
。真的有必要吗?
方法 EntityManager.getReference
returns 一个 Hibernate
代理,无需查询数据库和设置实体的属性。除非您尝试自己获取返回代理的属性。
方法JpaRepository.getOne
使用EntityManager.getReference
方法而不是EntityManager.find
方法。因此,每当您需要一个托管对象但实际上不需要为此查询数据库时,最好使用 JpaRepostory.getOne
方法来消除不必要的查询。
如果找不到特定 ID 的 table 数据,findOne 将 return 为 null,而 getOne 将抛出 javax.persistence.EntityNotFoundException。 两者各有利弊。请看下面的例子:
- 如果找不到数据对您来说不是失败案例(例如,您只是 验证数据是否被删除,成功将是数据 null),你可以使用 findOne.
- 另一种情况,你可以使用getOne。
如果您知道结果,可以根据您的要求进行更新。