我正在尝试在我的实体中进行批量删除,我认为最好的解决方案是使用CriteriaDelete
。但CriteriaDelete
不会级联(至少不适合我)。
所以似乎只有我要做的解决方案是先选择,然后单独删除每个元素。这对我来说似乎没有错。
有人有更好的想法如何进行批量删除吗?这实际上是更好的方式吗?
如果它有助于我使用eclipselink 2.5.2。
答案 0 :(得分:7)
选项包括:
答案 1 :(得分:5)
JPA CriteriaDelete
语句生成一个JPQL批量删除语句,该语句已解析为SQL批量删除语句。
因此,以下JPA CriteriaDelete
语句:
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaDelete<PostComment> delete = builder.createCriteriaDelete(PostComment.class);
Root<T> root = delete.from(PostComment.class);
int daysValidityThreshold = 3;
delete.where(
builder.and(
builder.equal(
root.get("status"),
PostStatus.SPAM
),
builder.lessThanOrEqualTo(
root.get("updatedOn"),
Timestamp.valueOf(
LocalDateTime
.now()
.minusDays(daysValidityThreshold)
)
)
)
);
int deleteCount = entityManager.createQuery(delete).executeUpdate();
生成此SQL删除查询:
DELETE FROM
post_comment
WHERE
status = 2 AND
updated_on <= '2020-08-06 10:50:43.115'
因此,由于删除操作是使用SQL语句而不是通过EntityManager
完成的,因此没有实体级级联。
要在执行批量删除时启用级联,则在声明FK约束时需要使用DDL级层叠。
ALTER TABLE post_comment
ADD CONSTRAINT FK_POST_COMMENT_POST_ID
FOREIGN KEY (post_id) REFERENCES post
ON DELETE CASCADE
现在,当执行以下批量删除语句时:
DELETE FROM
post
WHERE
status = 2 AND
updated_on <= '2020-08-02 10:50:43.109'
数据库将删除引用已删除的post_comment
行的post
记录。
执行DDL的最佳方法是通过自动模式迁移工具(例如Flyway),因此外键定义应驻留在迁移脚本中。
如果您正在使用HBM2DLL工具生成迁移脚本,那么在PostComment
类中,可以使用以下映射来生成上述DDL语句:
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(foreignKey = @ForeignKey(name = "FK_POST_COMMENT_POST_ID"))
@OnDelete(action = OnDeleteAction.CASCADE)
private Post post;
有关使用Criteria API批量更新和删除查询的更多详细信息,请查看this article。
答案 2 :(得分:3)
如果您真的关心执行批量删除所需的时间,我建议您使用JPQL删除您的实体。当您发出DELETE
JPQL查询时,它会直接在这些实体上发出删除,而不会首先检索它们。
int deletedCount = entityManager.createQuery("DELETE FROM Country").executeUpdate();
您甚至可以使用查询API(例如下面的
)基于这些实体上的某些参数进行条件删除Query query = entityManager.createQuery("DELETE FROM Country c
WHERE c.population < :p");
int deletedCount = query.setParameter(p, 100000).executeUpdate();
操作完成后, executeUpdate
将返回已删除行的数量。
如果您在CascadeType.ALL
(或)CascadeType.REMOVE
等实体中使用了适当的级联类型,则上述查询将为您提供帮助。
@Entity
class Employee {
@OneToOne(cascade=CascadeType.REMOVE)
private Address address;
}
答案 3 :(得分:2)
JPQL BULK DELETE
(无论是使用基于字符串的JPQL还是使用Criteria JPQL)不打算级联(即遵循字段的级联类型设置)。如果您想要级联,那么您可以将数据存储设置为使用真实FOREIGN KEY
,或者撤回要删除的对象并调用EntityManager.remove()
。