为什么Spring数据存储库上的getOne(...)不会抛出EntityNotFoundException?

Seb*_*Seb 23 java spring jpa spring-data spring-data-jpa

我正在处理一个奇怪的问题,我正在进行集成测试,调用我的控制器从数据库中获取一个不存在的对象.

public Optional<T> get(Long id) {

  try {
    return Optional.ofNullable(repository.getOne(id));
  } catch(EntityNotFoundException e) {
    return Optional.empty();
  }
}
Run Code Online (Sandbox Code Playgroud)

什么时候getOne(…)找不到什么东西,我一直在期待,EntityNotFoundException但实际上什么都没有.如果我检查我的结果,我可以看到我有一个空实体,其中有一个处理程序链接"扔EntityNotFoundException"但我们没有进入catch并且我返回一个可选的这个奇怪的实体.

我无法理解这种行为.

Oli*_*ohm 33

这是由于JPA指定EntityManager.getReference(…)的工作方式.它应该返回一个代理,它将在第一次访问属性时解析要返回的对象,或者最终抛出包含的异常.

解决这个问题最简单的方法就是简单地使用findOne(…),就像这样Optional.ofNullable(repository.findOne(…)).如果没有找到结果,findOne(…)将返回null.

解决此问题的更高级方法是使存储库Optional直接返回实例.这可以通过使用-methods的Optional<T>返回类型创建自定义基本存储库接口来实现find….

interface BaseRepository<T, ID extends Serializable> extends Repository<T, ID> {

  Optional<T> findOne(ID id);

  // declare additional methods if needed
}

interface YourRepository extends BaseRepository<DomainClass, Long> { … }
Run Code Online (Sandbox Code Playgroud)

Spring Data示例存储库中找到完整的示例.

  • 确实存在差异,因为`getOne(...)`不会立即实现对象,而`findOne(...)`就是这样.前者的缺点是它也会延迟查找失败,这会让你感到困惑.此外,`findOne(...)`将命中`EntityManager`中的第一级缓存,因此在特定会话中,您不会两次访问数据库.如果这确实成为一个问题,你可能想明确地插入一个缓存,但我会延迟,直到测量真的显示,这是一个问题. (5认同)
  • 很清楚,谢谢你的帮助! (2认同)

VK3*_*321 5

在 Spring@Repository类中,在getOne(id)查询对象(通过调用entity.getId()或其他方式)之前,该方法并不总是验证存在,因此它的无此类实体异常可能会延迟。要立即验证,请findById(id)改用(Optional<EntityType>如果具有该 id 的实体不存在,它将返回一个空值)。


这就是它对我的工作方式

public User findUserById(Long id) {
    return userRepository.findById(id).orElse(null);
}
Run Code Online (Sandbox Code Playgroud)