实体状态转换
JPA 将实体状态转换转换为 SQL 语句,例如 INSERT、UPDATE 或 DELETE。
当您 persist 一个实体时,您正在安排 INSERT 语句在 EntityManager 自动或手动刷新时执行。
当您remove 一个实体时,您正在调度 DELETE 语句,该语句将在刷新持久性上下文时执行。
级联实体状态转换
为方便起见,JPA 允许您将实体状态转换从父实体传播到子实体。
因此,如果您有一个父 Post 实体与 @OneToMany 关联与 PostComment 子实体:
Post实体中的comments集合映射如下:
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<Comment> comments = new ArrayList<>();
CascadeType.ALL
cascade 属性告诉 JPA 提供者将实体状态转换从父 Post 实体传递到 comments 集合中包含的所有 PostComment 实体。
因此,如果您删除 Post 实体:
Post post = entityManager.find(Post.class, 1L);
assertEquals(2, post.getComments().size());
entityManager.remove(post);
JPA 提供者将首先删除PostComment 实体,当所有子实体都被删除时,它也会删除Post 实体:
DELETE FROM post_comment WHERE id = 1
DELETE FROM post_comment WHERE id = 2
DELETE FROM post WHERE id = 1
孤儿删除
当您将orphanRemoval 属性设置为true 时,JPA 提供程序将在从集合中删除子实体时安排remove 操作。
所以,在我们的例子中,
Post post = entityManager.find(Post.class, 1L);
assertEquals(2, post.getComments().size());
PostComment postComment = post.getComments().get(0);
assertEquals(1L, postComment.getId());
post.getComments().remove(postComment);
JPA 提供程序将删除关联的 post_comment 记录,因为 PostComment 实体不再在 comments 集合中引用:
DELETE FROM post_comment WHERE id = 1
关于删除级联
ON DELETE CASCADE 在 FK 级别定义:
ALTER TABLE post_comment
ADD CONSTRAINT fk_post_comment_post_id
FOREIGN KEY (post_id) REFERENCES post
ON DELETE CASCADE;
一旦你这样做,如果你删除 post 行:
DELETE FROM post WHERE id = 1
数据库引擎会自动删除所有关联的post_comment 实体。但是,如果您错误地删除了根实体,这可能是一个非常危险的操作。
结论
JPA cascade 和 orphanRemoval 选项的优点是您还可以从乐观锁定中受益,以防止丢失更新。
如果您使用 JPA 级联机制,则无需使用 DDL 级别的ON DELETE CASCADE,如果您移除在多个级别上有许多子实体的根实体,这可能是非常危险的操作。