JPA——CascadeType.PERSIST

今天我们来学习一种简单的级联关系——CascadeType.PERSIST。
业务分析
首先,我们使用一个具体的业务场景,每个Post
内容都有一个PostDetails
细节,它们之间是一对一的关系,按照业务原则,我们来看看Post
和PostDetails
之间的关系是组合还是聚合,没有了Pos
t,那么PostDetails
没有存在的必要,因此PostDetails
没有单独存在的可能性。因此它们之间是组合关系。
代码展示
我们再来看看模型Post
的代码:
@Entity
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
@OneToOne(mappedBy = "post",
cascade = CascadeType.ALL, orphanRemoval = true)
private PostDetails details;
public Long getId() {
return id;
}
public PostDetails getDetails() {
return details;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void addDetails(PostDetails details) {
this.details = details;
details.setPost(this);
}
public void removeDetails(PostDetails details) {
if (details != null) {
details.setPost(null);
}
this.details = null;
}
}
模型PostDetails
的代码:
@Entity
public class PostDetails {
@Id
private Long id;
@Column(name = "created_on")
@Temporal(TemporalType.TIMESTAMP)
private Date createdOn = new Date();
private boolean visible;
@OneToOne
@MapsId
private Post post;
public Long getId() {
return id;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
public void setPost(Post post) {
this.post = post;
}
}
再来看看调用方:
public void savePostAndDetail() {
Post post = new Post();
post.setName("Hibernate Master Class");
PostDetails details = new PostDetails();
post.addDetails(details);
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction tx = entityManager.getTransaction();
tx.begin();
entityManager.persist(post);
tx.commit();
entityManager.close();
}
日志分析
执行调用方的代码后,我们看到的日志信息如下:
create table Post (
id bigint not null,
name varchar(255),
primary key (id)
)
Hibernate:
create table PostDetails (
created_on timestamp,
visible boolean not null,
post_id bigint not null,
primary key (post_id)
)
alter table PostDetails
add constraint FKxtdvogk47ve80had52g3dm8s
foreign key (post_id)
references Post
insert
into
Post
(name, id)
values
(?, ?)
Hibernate:
insert
into
PostDetails
(created_on, visible, post_id)
values
(?, ?, ?)
可以看到,因为在建模的时候使用的是双向关联,并且在PostDetails中使用的共享主键的方式,因此JPA在创建外键的时候是映射的@MapId映射出来的值,即post+Id,因此PostDetails的主键变成了post_id。
其次需要注意的是为什么说这里使用的是CascadeType.ALL
这是因为Post和PostDetails之间还存在另外一些关系,比如删除Post的时候,必定删除PostDetails。如果我配置成CascadeType.PERSIST
这个例子在这里还是没有问题的,但是如果删除的时候就不能级联删除了,另外如果需要更新的时候,也不能级联更新。这破坏了模型的一些约定。
再次Post
实体扮演Parent
角色,PostDetails
是 Child
。在这种特殊情况下,CascadeType.ALL 和orphan removal是有意义的,因为 PostDetails 生命周期绑定到其 Post Parent 实体的生命周期。
双向关联应始终在两侧更新,因此父端应包含 addChild 和 removeChild 组合。这些方法确保我们始终同步关联的双方,以避免对象或关系数据损坏问题。
总结如下
1、在JPA中配置级联的时候需要具体根据业务模型的业务来进行配置,通常情况下配置成CascadeType.ALL
一般不会存在什么问题。但是如果有些业务只有新增的话,那么配置成CascadeType.PERSIST
会是一个更好的选择
2、这里JPA会生成相应的外键,而这个外键并不是在PostDetails中配置的id,而是通过映射关系生成的。
版权声明:著作权归作者所有。