sql - deleteAll() 与 deleteAllInBatch() 在带有“@Where”子句的休眠实体上产生不同的结果
问题描述
在具有多对一关系的实体上使用 JpaRepositorydeleteAll()
生成(其中“一个”具有 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
extends 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()
休眠执行相同的绑定,但仅适用于“启用”客户。
这是一个错误还是预期的行为?如果这是预期的,有人可以解释为什么它会这样工作吗?
解决方案
我们遇到了类似的情况,“删除”了带有注释的实体实例@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)更准确,简单地说。
推荐阅读
- excel - 特定范围的条件锁定
- c++ - 带有 lambda 函数参数的重载模板函数的语法
- elasticsearch - Elasticsearch搜索孩子并报告父母和孩子的查询语法应该是什么
- python - 如何在多个 csv 文件的 glob 操作期间有效地填充
- javascript - JSON数据到时间
- visual-studio-code - 如何找到所有违反 eslint 规则的案例?
- python - 在所有缩放级别上保持椭圆形
- c# - 在启动时运行一个应用程序,该应用程序使用我的 url 打开浏览器,并且不要让用户关闭浏览器或应用程序
- c# - 在通用类型的通用列表 Blazor C# 中更改动态选择的 Div 类
- javascript - Chrome 不播放仅支持 `http` 协议的源