You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

迁移至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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 12:23:23