使用带嵌入式ID的JPA实体删除数据库行失败排查
问题描述
我正在开发一款基于Java的后端应用,技术栈包含JPA、Rest、Hibernate、Spring Boot。当关联的Item被删除时,我调用deleteParameterById方法删除Parameter记录,日志显示参数ID已正确传入,但Swagger测试始终返回“Data Was Not Found”提示。这是我首次尝试删除带Embedded Id的实体记录,查询无法正常执行。
现有代码
删除方法(JPQL版本)
@Override @Transactional public void deleteParameterById(Long parameterId) { Query query = entityManager .createQuery("DELETE FROM ParameterEntity pa WHERE pa.ParameterEntityId.parameterId = ?1"); query.setParameter(1, parameterId) .executeUpdate(); }
嵌入式ID类(ParameterEntityId.java)
@Embeddable public class ParameterEntityId implements Serializable { @Column(name = "PARAMETER_ID") private Long parameterId; @Column(name = "PARAMETER_ATTRIBUTE_TYPE_ID") private Long parameterAttributeTypeId; }
实体类(ParameterEntity.java)
@Entity @Table(name = "parameter") public class ParameterEntity { @EmbeddedId private ParameterEntityId parameterEntityId; @Column(name = "VALUE") private String value; }
原生SQL版本删除方法
@Override @Transactional public void deleteParameterById(Long parameterId) { entityManager.createNativeQuery("DELETE FROM *dbname(redacted)*.parameter WHERE parameter_id = ?1") .setParameter(1, parameterId).executeUpdate(); }
我查阅的示例多采用JPA Repository实现,但本应用未配置该方式。用原生SQL尝试删除时,请求一直处于“processing”状态,已确认应用具备表的编辑与删除权限。
请问哪里操作出错了?
问题分析与解决
1. JPQL查询的核心错误
JPQL中引用实体属性必须严格匹配Java代码的变量名大小写:你的实体类里嵌入式ID字段是parameterEntityId(小写p开头),但查询语句里写的是pa.ParameterEntityId.parameterId(大写P开头),这会导致Hibernate无法识别该属性,查询找不到任何匹配数据,最终返回“Data Was Not Found”。
修正后的JPQL删除代码:
@Override @Transactional public void deleteParameterById(Long parameterId) { Query query = entityManager .createQuery("DELETE FROM ParameterEntity pa WHERE pa.parameterEntityId.parameterId = ?1"); query.setParameter(1, parameterId) .executeUpdate(); }
2. 原生SQL查询的阻塞问题
原生SQL请求一直处于“processing”状态,主要有两个可能原因:
- 语法错误:SQL里的
*dbname(redacted)*写法不符合数据库规范,比如MySQL应直接写DELETE FROM dbname.parameter,去掉星号; - 事务或锁等待:检查
@Transactional注解的传播机制是否正确,确保方法在有效事务中执行;同时排查数据库是否存在未释放的行锁,比如其他事务占用了待删除数据的锁,导致当前请求阻塞。
3. 调试验证方案
如果还是无法定位问题,可以先查询再删除,明确数据是否存在:
@Override @Transactional public void deleteParameterById(Long parameterId) { // 先查询匹配记录 List<ParameterEntity> entities = entityManager.createQuery( "SELECT pa FROM ParameterEntity pa WHERE pa.parameterEntityId.parameterId = ?1", ParameterEntity.class ).setParameter(1, parameterId).getResultList(); if (!entities.isEmpty()) { entities.forEach(entityManager::remove); } else { throw new RuntimeException("Data Was Not Found"); } }
这种方式能直观确认是否存在待删除数据,方便排查逻辑问题。
内容的提问来源于stack exchange,提问作者Mtullis
相关产品推荐
相关产品推荐

