迁移至Spring Boot3后Hibernate删除实体不抛出EntityNotFoundException问题
Spring Boot 3 + Hibernate 6 删除实体后
getOne()未抛出预期EntityNotFoundException问题 在Spring应用中,我们通过通用仓库测试验证Spring Data JPA仓库的基础功能,其中一项测试用于验证获取已删除实体时是否抛出EntityNotFoundException。但迁移至Spring Boot 3和Hibernate 6后,原本正常运行的测试不再抛出预期异常。
可复现问题的代码配置
1. 实体类 Entity.java
package de.test.hibernate_delete.repository; import jakarta.persistence.*; @Entity @Table(name = "entity") public class Entity { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) private Long id; @Version private long version; @Column(name = "data") private String data; public Entity(String data) { this.data = data; } public Entity() {} // Getter和Setter方法 public Long getId() {return id;} public void setId(Long id) {this.id = id;} public long getVersion() {return version;} public void setVersion(long version) {this.version = version;} public String getData() {return data;} public void setData(String data) {this.data = data;} }
2. 仓库接口 EntityRepository.java
package de.test.hibernate_delete.repository; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface EntityRepository extends JpaRepository<Entity, Long> { }
3. 测试用例 EntityDeleteTest.java
package de.test.hibernate_delete; import de.test.hibernate_delete.repository.Entity; import de.test.hibernate_delete.repository.EntityRepository; import jakarta.persistence.EntityNotFoundException; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import static org.junit.jupiter.api.Assertions.*; @SpringBootTest(classes = HibernateDeleteApplication.class) public class EntityDeleteTest { @Autowired private EntityRepository repository; @Test public void testDelete() { Entity storedSample = repository.saveAndFlush(new Entity("data")); assertNotNull(storedSample.getId()); repository.delete(storedSample); repository.flush(); // 预期抛出EntityNotFoundException,但未触发 assertThrows(EntityNotFoundException.class, () -> assertNull(repository.getOne(storedSample.getId()))); } }
测试报错信息
org.opentest4j.AssertionFailedError: Unexpected exception type thrown, Expected :class jakarta.persistence.EntityNotFoundException Actual :class org.opentest4j.AssertionFailedError
解决方案:修改测试用例
参考社区建议,调整测试逻辑,不再依赖getOne()的异常抛出,改为直接验证实体是否存在:
@Test public void testDelete() { // 保存并刷新实体 Entity storedSample = repository.saveAndFlush(new Entity("data")); assertNotNull(storedSample.getId()); // 删除实体并刷新 repository.delete(storedSample); repository.flush(); // 验证实体已不存在于数据库 assertFalse(repository.existsById(storedSample.getId())); }
原因说明
Spring Data JPA 3.x(对应Spring Boot 3)中,getOne()方法的实现发生了变化:它现在返回懒加载代理对象,即使实体已被删除,只要未触发代理的初始化(比如调用实体的Getter方法),就不会抛出EntityNotFoundException。而旧版本中getOne()会立即检查实体存在性并抛出异常。
也可以改用findById()结合Optional来验证:
// 另一种测试方式:使用findById触发存在性检查 assertThrows(NoSuchElementException.class, () -> repository.findById(storedSample.getId()).orElseThrow());
内容的提问来源于stack exchange,提问作者WorkingAccount
相关产品推荐
相关产品推荐

