Spring / Hibernate - 删除实体时抛出 StaleStateException
Posted
技术标签:
【中文标题】Spring / Hibernate - 删除实体时抛出 StaleStateException【英文标题】:Spring / Hibernate - StaleStateException thrown when deleting entity 【发布时间】:2021-06-09 07:43:31 【问题描述】:我的一个实体在尝试删除它时抛出了 StaleStateException。有问题的代码:
@RestController
@RequestMapping("/cycles")
public class DeleteCycleController
@DeleteMapping("cycleId")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteCycleById(@PathVariable("cycleId") UUID cycleId, Principal principal)
// cycleRepository extends CrudRepository
cycleRepository.deleteById(new CycleId(cycleId));
// deleter.deleteCycle(new CycleId(cycleId));
抛出以下内容:
org.springframework.orm.ObjectOptimisticLockingFailureException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; statement executed: HikariProxyPreparedStatement@716092925 wrapping delete from cycle where id='c4c1428e-c296-4199-85f6-8ef16e6999c9'::uuid; nested exception is org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; statement executed: HikariProxyPreparedStatement@716092925 wrapping delete from cycle where id='c4c1428e-c296-4199-85f6-8ef16e6999c9'::uuid
以下是失败前的休眠日志:
2021-03-11 20:34:11.532 DEBUG 55483 --- [nio-8080-exec-7] org.hibernate.SQL : requestId=b53dd96089f748cf942fc46867d32fb5, requestMethod=DELETE, correlationId=b53dd96089f748cf942fc46867d32fb5, requestURI=/cycles/c4c1428e-c296-4199-85f6-8ef16e6999c9, userId=5ae11e82-f8df-4fad-ae10-1aa57423ba31, orgId=c7389774-9afa-452b-aa1c-74e7b18bc04d : select cycle0_.id as id1_0_0_, cycle0_.attributes as attribut2_0_0_, cycle0_.created_at as created_3_0_0_, cycle0_.cycle_type_id as cycle_ty4_0_0_, cycle0_.description as descript5_0_0_, cycle0_.end_time as end_time6_0_0_, cycle0_.start_time as start_ti7_0_0_, cycle0_.end_location as end_loca8_0_0_, cycle0_.last_modified_at as last_mod9_0_0_, cycle0_.name as name10_0_0_, cycle0_.organization_id as organiz11_0_0_, cycle0_.start_location as start_l12_0_0_ from cycle cycle0_ where cycle0_.id=?
Hibernate: select cycle0_.id as id1_0_0_, cycle0_.attributes as attribut2_0_0_, cycle0_.created_at as created_3_0_0_, cycle0_.cycle_type_id as cycle_ty4_0_0_, cycle0_.description as descript5_0_0_, cycle0_.end_time as end_time6_0_0_, cycle0_.start_time as start_ti7_0_0_, cycle0_.end_location as end_loca8_0_0_, cycle0_.last_modified_at as last_mod9_0_0_, cycle0_.name as name10_0_0_, cycle0_.organization_id as organiz11_0_0_, cycle0_.start_location as start_l12_0_0_ from cycle cycle0_ where cycle0_.id=?
2021-03-11 20:34:11.533 TRACE 55483 --- [nio-8080-exec-7] o.h.type.descriptor.sql.BasicBinder : requestId=b53dd96089f748cf942fc46867d32fb5, requestMethod=DELETE, correlationId=b53dd96089f748cf942fc46867d32fb5, requestURI=/cycles/c4c1428e-c296-4199-85f6-8ef16e6999c9, userId=5ae11e82-f8df-4fad-ae10-1aa57423ba31, orgId=c7389774-9afa-452b-aa1c-74e7b18bc04d : binding parameter [1] as [OTHER] - [c4c1428e-c296-4199-85f6-8ef16e6999c9]
2021-03-11 20:34:11.542 DEBUG 55483 --- [nio-8080-exec-7] org.hibernate.SQL : requestId=b53dd96089f748cf942fc46867d32fb5, requestMethod=DELETE, correlationId=b53dd96089f748cf942fc46867d32fb5, requestURI=/cycles/c4c1428e-c296-4199-85f6-8ef16e6999c9, userId=5ae11e82-f8df-4fad-ae10-1aa57423ba31, orgId=c7389774-9afa-452b-aa1c-74e7b18bc04d : delete from cycle where id=?
Hibernate: delete from cycle where id=?
2021-03-11 20:34:11.542 TRACE 55483 --- [nio-8080-exec-7] o.h.type.descriptor.sql.BasicBinder : requestId=b53dd96089f748cf942fc46867d32fb5, requestMethod=DELETE, correlationId=b53dd96089f748cf942fc46867d32fb5, requestURI=/cycles/c4c1428e-c296-4199-85f6-8ef16e6999c9, userId=5ae11e82-f8df-4fad-ae10-1aa57423ba31, orgId=c7389774-9afa-452b-aa1c-74e7b18bc04d : binding parameter [1] as [OTHER] - [c4c1428e-c296-4199-85f6-8ef16e6999c9]
还有 Cycle 实体:
@javax.persistence.Entity
@Accessors(fluent = true)
@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@Builder
@TypeDefs(@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class))
public class Cycle
@Id private UUID id;
private CycleName name;
private CycleDescription description;
private UUID cycleTypeId;
private UUID organizationId;
private Instant createdAt;
private Instant lastModifiedAt;
@Type(type = "jsonb")
private Map<String, Object> attributes;
private CycleDuration duration;
@Column(columnDefinition = "Geometry", nullable = true)
private Geometry startLocation;
private Geometry endLocation;
@OneToMany(mappedBy = "cycleId", cascade = CascadeType.ALL, orphanRemoval = false)
@Getter(AccessLevel.PRIVATE)
@Setter(AccessLevel.PUBLIC)
private List<CycleEntityMapping> entities = new ArrayList<>();
...
关于可能出现什么问题的任何想法?另一个(更简单的)实体删除得很好。
不确定它是否是 OneToMany 引起的问题,但我尝试更改级联类型、孤儿删除和获取类型,但没有成功。否则会不会是值对象造成的?请注意,更新实体工作正常 - 它只是在删除时失败。
【问题讨论】:
你传递给 repo 的“new CycleId”是什么? 我们将 UUID 包装在对象中,在内部循环存储库调用cycleJPARepository.deleteById(cycleId.id());
其中 cycleId.id()
返回 UUID
异常表示数据库中不存在该记录。记录还在吗?它在哪里起作用,还有 UUID 作为 PK 使用的吗?
经过进一步调查,似乎是由删除前触发器引起的。触发器将删除的行复制到另一个表中。删除触发器可以解决问题。不知道为什么触发器会导致这个问题
刚刚进一步调查 - 结果是触发器将其复制到存档表,但由于错误(return new
而不是return old
)而没有从现有表中删除。将其更改为 return old
可以解决问题
【参考方案1】:
在这种情况下,它是由删除前触发器中的错误引起的。触发器中有一个错误导致该行未被删除:
CREATE OR REPLACE FUNCTION trigger_delete_row_backup()
RETURNS trigger AS
$BODY$
BEGIN
INSERT INTO deleted_cycle values (OLD.*);
RETURN NEW;
-- should actually be RETURN OLD
END;
$BODY$
language PLPGSQL;
一旦触发器被修复,问题就解决了。
【讨论】:
以上是关于Spring / Hibernate - 删除实体时抛出 StaleStateException的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Spring Data JPA(Hibernate) 跨映射表过滤关联实体?
Spring/Hibernate:保存后是不是必须加载实体才能使用它?
spring+hibernate集成动态修改表结构,网上要对LocalSessionFactory进行小小的修改