sql - deleteAll() 与 deleteAllInBatch() 在带有 '@Where' 子句的 hibernate 实体上产生不同的结果

标签 sql hibernate jpa spring-data-jpa

使用 JpaRepository deleteAll()生产 org.springframework.orm.jpa.JpaObjectRetrievalFailureException在具有多对一关系的实体上(其中“one”有一个 where 子句)

我正在使用 @Where在实体上执行软删除的子句:

@Where(clause = "enabled = true")
@Table(name = "customer")
public class CustomerEntity {
...
}

有一个@ManyToOneCustomerEntity 的关系在另一个实体上:

@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 正在为所有客户执行以下绑定(bind)(即使未启用):
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 执行相同的绑定(bind),但仅针对“启用”的客户。

这是一个错误还是预期的行为?如果这是预期的,有人可以解释为什么它会这样工作吗?

最佳答案

我们遇到了类似的情况,“删除”了带有 @Where(clause = "deleted = false") 注释的实体实例。 .如果那些被另一个实体引用,与后者一起工作会导致提到的相同 javax.persistence.EntityNotFoundException .

也许我错了,但是当您通过 BirthdayEventRepository 加载事件时应该会看到相同的错误。然后访问它的CustomerEntity .

我只能从文档中猜测 CrudRepository.deleteAll在删除它们之前加载所有事件,而 JpaRepository.deleteAllInBatch没有。

CrudRepository.deleteAll

void deleteAll()

Deletes all entities managed by the repository.



JpaRepository.deleteAllInBatch

void deleteAllInBatch()

Deletes all entities in a batch call.



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)更快,因为它不执行检查, while(1) 更准确,简单地说。

关于sql - deleteAll() 与 deleteAllInBatch() 在带有 '@Where' 子句的 hibernate 实体上产生不同的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59302788/

相关文章:

sql - 使用 NOT EXISTS 接受所有贷款的借款人

php - Sql Count(*) 单个查询中每个 id 的相关项目数

java - ehcache hibernate二级缓存,hibernate自动驱逐

java - 如何查找按日期排序的 List<Object>

spring - 如何不允许从跨国方法之外延迟加载?

c# - 如何修复 "Violation of UNIQUE KEY constraint"

sql - 在更新语句中加密 postgres 列

hibernate - Spring MVC Hibernate + SQLite 不创建数据库

java - 如何在没有 hibernate.cfg.xml 文件的情况下创建 Hibernate session ?

java - JPA:@PrimaryKeyJoinColumn(...) 与@JoinColumn(..., insertable = ?, updatable = ?) 一样吗?