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

Spring JPA删除实体后保存抛出EntityNotFoundException解决方案

问题场景

多个数据表通过项目ID关联同一个Project实体,重新加载已存在ID的Project时,需要先清空数据库中该项目下所有关联实体数据。

Controller层代码

@CrossOrigin
@RequestMapping(value = "projects", method = RequestMethod.POST)
public ResponseEntity<?> uploadProject(MultipartFile file) {
    JsonDataDto projectDto = converterService.convertToDto(file, JsonDataDto.class);
    
    if(projectRepository.exists(projectDto.getId())) {
        // 从数据库删除该项目下所有关联实体
        projectService.delete(projectDto.getId());
    }

    // 将项目保存到数据库
    importService.import(projectDto);
}

Project Service删除逻辑代码

@Service
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
public class GenericProjectService implements ProjectService {
    // 成员变量省略

    @Override
    public void delete(UUID projectId) {
        entity1Repository.deleteByProjectId(projectId)
        ...
        // 大部分实体通过外键关联项目,部分无外键的实体(比如Entity1)需要手动调用Repository删除
        // 所有关联实体删完后最后删除Project本身
        projectRepository.delete(projectId);
    }
}

说明:大部分实体通过外键关联项目,部分无外键的实体(如Entity1)需手动调用Repository删除,最后删除Project本体。

Import Service保存逻辑代码

@Service
public class GenericImportService implements ImportService {
    // 成员变量省略

    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
    public void import(JsonDataDto projectDto)  {
        Collection<Entity1> entity1 = projectDto.getEntity1()
                                                .stream().map(e -> e1Repository.save(e1Mapper.to(e))).collect(...);

        Map<UUID, Type> types = new HashMap<>();
        Map<UUID, TypeDto> typeDtosById = projectDto.getTypes().stream()
            .collect(Collectors.toMap(TypeDto::getId, Function.identity()));

        for (UUID typeId : typeDtosById.keySet()) {
            saveType(typeId, typeDtosById, types, ...);
        }
    }

    private void saveType(...) {
        Type type = new Type();

        // 赋值字段、设置关联关系

        // 此处抛出异常
        type = typeRepository.save(type);
        types.put(typeId, type);
    }
}

异常在saveType方法执行typeRepository.save(type)时抛出。

Type实体类代码

@Entity
@Data
@Table(name = "...", schema = "...")
public class Type {
    @Id
    private TypePK typeId;
    /*
        @Data
        @NoArgsConstructor
        @AllArgsConstructor
        @Embeddable
        public class TypePK implements Serializable {
            @Type(type = "pg-uuid")
            @Column(name = "id")
            private UUID id;

            @ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
            @JoinColumn(name = "project_id", insertable = false, updatable = false)
            private Project project;
        }
    */

    // 其他字段省略

    @org.hibernate.annotations.Type(type = "pg-uuid")
    @Column(name = "parent_id")
    private UUID parentId;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumns({
        @JoinColumn(name = "parent_id", referencedColumnName = "id", updatable = false, insertable = false), 
        @JoinColumn(name = "project_id", referencedColumnName = "project_id", updatable = false, insertable = false)})
    private Type parent;
}

Type实体使用复合主键TypePK,包含自关联parent字段。

异常现象
  • 数据库中不存在对应项目时,保存操作可以正常执行;单独调用删除接口也能正常删除数据库中的项目数据。
  • 同一请求流程中先删除已存在的项目,再执行导入保存时,抛出错误:Unable to find package.Type with id TypePK(id=7e8281fe-77b8-475d-8ecd-c70522f5a403, project=Project(id=8d109d33-e15e-ca81-5f75-09e00a81a194))。
  • 抛出异常时对应实体实际已经从数据库中移除,但保存操作的事务会被回滚。
已尝试方案
  • 尝试在删除操作后手动调用TransactionStatus的flush方法强制刷新事务,未生效:
public void delete(UUID projectId) {
    TransactionStatus ts = TransactionAspectSupport.currentTransactionStatus();
    entity1Repository.deleteByProjectId(projectId)
    ...
    ts.flush();
}
  • 目前仅能通过删除后等待2秒再执行保存的临时方案规避问题,属于权宜之计,需要找到问题根因和规范的解决方案。

内容的提问来源于stack exchange,提问作者Shadow4571

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 19:12:42