Spring Data JPA 中 getOne、findById、findOne 的区别

本文介绍了SpringData JPA中的四种查询方法:getOne、findById、findOne及其应用场景。getOne采用延迟加载,找不到记录时抛出异常;findById立即加载,找不到返回Optional.empty();findOne也立即加载,适用于非ID查询及动态查询。
部署运行你感兴趣的模型镜像

1、getOne 方法(为null时会报错慎用

getOne 是一个延迟加载方法,它并不立即访问数据库,而是返回一个代理(proxy)对象,这个代理对象是对实体对象的引用,仅在 使用代理对象访问对象属性时才会去真正访问数据库 ,如果找不到,则抛出 EntityNotFoundException

源码:

public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
	/**
	 * Returns a reference to the entity with the given identifier. Depending on how the JPA persistence provider is
	 * implemented this is very likely to always return an instance and throw an
	 * {@link javax.persistence.EntityNotFoundException} on first access. Some of them will reject invalid identifiers
	 * immediately.
	 *
	 * @param id must not be {@literal null}.
	 * @return a reference to the entity with the given identifier.
	 * @see EntityManager#getReference(Class, Object) for details on when an exception is thrown.
	 */
	T getOne(ID id);
}

2、findById 方法

findById 方法会立即(EAGER)访问数据库,并返回和指定 ID 关联的实体对象;如果没有找到,则返回 Optional.empty()

源码:

public interface CrudRepository<T, ID> extends Repository<T, ID> {	
	/**
	 * Retrieves an entity by its id.
	 *
	 * @param id must not be {@literal null}.
	 * @return the entity with the given id or {@literal Optional#empty()} if none found.
	 * @throws IllegalArgumentException if {@literal id} is {@literal null}.
	 */
	Optional<T> findById(ID id);
}

3、findOne 方法

除了 findByIdgetOne 外,Spring Data JPA 还提供了两个 findOne 方法:

  • Optional<T> findOne(@Nullable Specification<T> spec)
  • <S extends T> Optional<S> findOne(Example<S> example)

这两个方法用于需要动态构建多条件查询的场景中,它们都是立即访问数据库的。

返回类型为 Optional ,如果没有检索到,返回 Optional.empty(),结果满足条件的记录条数超过一条,则抛出 IncorrectResultSizeDataAccessException

源码:

public interface QueryByExampleExecutor<T> {
/**
	 * Returns a single entity matching the given {@link Example} or {@literal null} if none was found.
	 *
	 * @param example must not be {@literal null}.
	 * @return a single entity matching the given {@link Example} or {@link Optional#empty()} if none was found.
	 * @throws org.springframework.dao.IncorrectResultSizeDataAccessException if the Example yields more than one result.
	 */
	<S extends T> Optional<S> findOne(Example<S> example);
}
public interface JpaSpecificationExecutor<T> {
/**
	 * Returns a single entity matching the given {@link Specification} or {@link Optional#empty()} if none found.
	 *
	 * @param spec can be {@literal null}.
	 * @return never {@literal null}.
	 * @throws org.springframework.dao.IncorrectResultSizeDataAccessException if more than one entity found.
	 */
	Optional<T> findOne(@Nullable Specification<T> spec);
}

4、findOne 使用样例

​ 4.1 findOne(@Nullable Specification<T> spec);

Optional<User> user =
        postRepository.findOne(
            (root, query, cb) ->
                cb.and(cb.equal(root.get("openId"), "aaa"), cb.equal(root.get("state"), 1)));

​ 4.2 findOne(Example<S> example);

User u = new User();
u.setOpenId("xxx");
u.setState(1);
Example<User> example = Example.of(u);
Optional<User> user = postRepository.findOne(example);

以上两种写法是等效的,执行的 SQL 如下:

Hibernate: select user0_.id as id1_0_, user0_.created_at as created_2_0_, user0_.open_id as open_id3_0_, user0_.state as state4_0_ from t_users user0_ where user0_.open_id=? and user0_.state=1

5、总结

1、getOne 是延迟加载;而 findByIdfindOne 是立即加载。

2、 getOne 如果找不到记录会抛出EntityNotFoundException;而 findByIdfindOne 会返回 Optional.empty()

3、 在 @ManyToOne 的场景中使用 findOne ,可以获得延迟加载机制带来的性能优势。

4、 在根据非 ID 查询、或动态查询的场景中,使用 findOne

5、 findOne 查询结果不能返回超过一条,否则会抛出 IncorrectResultSizeDataAccessException

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

<think>我们正在处理一个关于Spring Data JPAfindOne方法的使用问题。根据提供的引用,我们可以总结出以下关键点: 1. 在Spring Data JPA的早期版本中,`findOne`方法用于根据ID查询单个实体。 2. 在2.0.5版本之后,`findOne`方法不再用于根据ID查询,而是被`findById`方法替代,使用方式为`findById(id).get()`(注意:`get()`会直接返回实体,如果不存在则抛出异常,而更安全的方式是使用`orElse(null)`等)。 3. 另外,引用[4]提到`findOne`方法现在在`QueryByExampleExecutor`接口中,用于按示例查询,返回一个`Optional`。 4. 引用[5]提到了`findOne`与`findById`、`getOne`的区别。 因此,我们需要向用户解释清楚: - 当前版本中,根据ID查询单个实体应该使用`findById`方法,它返回一个`Optional`,我们可以通过`get()`方法获取实体(但要注意如果不存在会抛出异常),或者使用`orElse`等方法提供默认值。 - 而`findOne`方法现在用于按示例查询(Example查询),它同样返回一个`Optional`。 另外,根据引用[2][3],我们还可以提到Spring Data JPA的命名规则,即查询方法以`findBy`开头,后面跟属性名和条件。 所以,回答结构如下: 1. 介绍`findOne`方法的历史变化。 2. 说明当前版本中根据ID查询的正确方法(使用`findById`)。 3. 说明当前版本中`findOne`方法的使用场景(按示例查询)。 4. 给出代码示例。 同时,我们还需要生成相关问题。 注意:回答中引用的段落末尾要自然地添加引用标识。 下面开始回答:</think>### Spring Data JPA `findOne()` 方法使用指南 #### 1. **方法的历史演变** - **旧版(<2.0.5)**:`findOne(id)` 直接通过 ID 查询实体,返回实体对象或 `null`。 - **新版(≥2.0.5)**:`findOne(id)` 被弃用,改为 `findById(id)`,返回 `Optional<T>` 包装对象[^1][^4]。 示例: ```java User user = userRepository.findById(1L).orElse(null); // 安全获取 ``` #### 2. **新版 `findById()` 的正确用法** - **基础查询**: ```java Optional<User> optionalUser = userRepository.findById(1L); ``` - **安全处理**: ```java User user = optionalUser.orElseThrow(() -> new EntityNotFoundException("用户不存在")); // 或 User user = optionalUser.orElse(new User()); // 返回默认值 ``` #### 3. **`findOne()` 的替代场景(按示例查询)** 新版 `findOne()` 迁移至 `QueryByExampleExecutor` 接口,用于**动态条件查询**[^4][^5]: ```java Example<User> example = Example.of( new User(null, "John", null), // 查询条件:name="John" ExampleMatcher.matching().withIgnorePaths("id") // 忽略id字段 ); Optional<User> user = userRepository.findOne(example); // 返回Optional ``` #### 4. **与 `getOne()` 的区别** - `getOne(id)`:返回**惰性加载的代理对象**(`getReference`),访问属性时才查数据库,可能抛 `LazyInitializationException`[^5]。 - `findById(id)`:**立即查询数据库**,返回实体或 `Optional.empty()`。 #### 5. **自定义查询方法** 遵循 `findBy + 属性名` 命名规则[^2][^3]: ```java public interface UserRepository extends JpaRepository<User, Long> { // 根据名称精确查询 User findByUsername(String username); // 多条件查询 List<User> findByAgeGreaterThanAndStatus(int age, String status); } ``` --- ### 常见问题解决 - **`findOne() not found` 错误**:升级后需替换为 `findById()`[^1]。 - **返回结果不匹配**:确保查询条件唯一,否则抛 `IncorrectResultSizeDataAccessException`[^5]。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值