okn*_*kno 5 sql hibernate jpa spring-data-jpa
使用 JpaRepository在具有多对一关系的实体上deleteAll()生成(其中“一”有一个 where 子句)org.springframework.orm.jpa.JpaObjectRetrievalFailureException
我正在@Where实体上使用子句来执行软删除:
@Where(clause = "enabled = true")
@Table(name = "customer")
public class CustomerEntity {
...
}
与另一个实体有@ManyToOne关系:CustomerEntity
@Entity
public abstract class CustomerEvent extends Event {
    @ManyToOne
    @JoinColumn(name = "customer_id")
    private CustomerEntity customer;
...
}
使用以下存储库(BirthdayEvent扩展CustomerEvent):
@Repository
public interface BirthdayEventRepository extends JpaRepository<BirthdayEvent, Integer> {
  ...
}
现在假设 ID 为“1”的客户有enabled = false一个与该客户关联的生日活动。
执行birthdayEventRepository.deleteAll()会产生如下错误:
org.springframework.orm.jpa.JpaObjectRetrievalFailureException: Unable to find org.example.app.entity.roles.customer.CustomerEntity with id 1; nested exception is javax.persistence.EntityNotFoundException: Unable to find org.example.app.entity.roles.customer.CustomerEntity with id 1
另一方面,使用deleteAllInBatch()效果很好。
尝试检查 Hibernate SQL 跟踪,我发现在该deleteAll()方法上,hibernate 正在为所有客户执行以下绑定(即使未启用):
2019-12-12 10:57:20.204 TRACE 2545551 --- [pool-4-thread-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BIGINT] - [1]
使用deleteAllInBatch()hibernate 执行相同的绑定,但仅适用于“已启用”的客户。
这是一个错误还是预期的行为?如果这是预期的,有人可以解释为什么它会这样工作吗?
Ste*_*bek 10
我们遇到了类似的情况,即用 注释的实体的“已删除”实例@Where(clause = "deleted = false")。如果这些被另一个实体引用,那么与后者合作会导致相同的结果javax.persistence.EntityNotFoundException。
也许我错了,但是在通过加载事件BirthdayEventRepository然后访问其CustomerEntity.
我只能从文档中猜测,CrudRepository.deleteAll在删除事件之前加载所有事件,而JpaRepository.deleteAllInBatch不会。
void deleteAll()删除存储库管理的所有实体。
JpaRepository.deleteAllInBatch
void deleteAllInBatch()删除批量调用中的所有实体。
更新2019-12-13
我很好奇,设置了一个测试并使用分析器记录了数据库访问。
1)deleteAll()首先从数据库中加载/选择所有记录:
exec sp_executesql N'select user0_.id as id1_11_, ... from [user] user0_'
接下来是一些其他读取来加载/检查引用的对象。然后它开始删除一个对象和另一个对象:
exec sp_executesql N'delete from [user] where id=@P0        ',N'@P0 bigint',1
exec sp_executesql N'delete from [user] where id=@P0        ',N'@P0 bigint',2
2) 相反,deleteAllInBatch()尝试直接删除所有实例:
exec sp_executesql N'delete from [user]'
简而言之,结论是(2)速度更快,因为它不执行检查,而(1)更准确。
| 归档时间: | 
 | 
| 查看次数: | 8400 次 | 
| 最近记录: |