JPA——CascadeType.PERSIST

选中文字可对指定文章内容进行评论啦,绿色背景文字可以点击查看评论额。

今天我们来学习一种简单的级联关系——CascadeType.PERSIST。

业务分析

首先,我们使用一个具体的业务场景,每个Post内容都有一个PostDetails细节,它们之间是一对一的关系,按照业务原则,我们来看看PostPostDetails之间的关系是组合还是聚合,没有了Post,那么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角色,PostDetailsChild。在这种特殊情况下,CascadeType.ALL 和orphan removal是有意义的,因为 PostDetails 生命周期绑定到其 Post Parent 实体的生命周期。

双向关联应始终在两侧更新,因此父端应包含 addChild 和 removeChild 组合。这些方法确保我们始终同步关联的双方,以避免对象或关系数据损坏问题。

总结如下

1、在JPA中配置级联的时候需要具体根据业务模型的业务来进行配置,通常情况下配置成CascadeType.ALL一般不会存在什么问题。但是如果有些业务只有新增的话,那么配置成CascadeType.PERSIST会是一个更好的选择

2、这里JPA会生成相应的外键,而这个外键并不是在PostDetails中配置的id,而是通过映射关系生成的。


 

 

版权声明:著作权归作者所有。

相关推荐

Spring JPA报错:Not supported for DML operations

在一个Spring JPA项目中,执行更新或删除是报错:Not supported for DML operations解决方法:只需要添加注解@Modifying即可。@Modifying@Query(value = "update User user set user.address = :address where user.id = :id ")void updateUserAddress

JPA Hibernate 快速入门

为了学习JPA的实体状态的转化,我们先搭建一个通过JPA Hibernate存储实体到数据库的Demo,后续的学习都在此demo基础上展开。添加Hibernate依赖 <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager&l

JPA架构(JPA - Architecture)

今天我们来学习一下JPA的架构,首先问一个问题,大家学习理解一个架构有什么好的方法呢?对于我自己来说,我觉得架构图是理解架构最好的方式以上就是JPA的架构图,我们可以知道,JPA的主要部分包括五个类: 第一个类EntityManagerFactory,我们可以称为实体管理器工厂类,很显然,这个类的作用是创建和管理多个实体管理器类,因此,我们可以大胆猜测,实体管理器工厂类和实体管理器是一对

JPA实体状态深入理解

我们在学习JPA实体状态的时候,常常会问,JPA的实体有多少状态呢?相信这个问题不难回答:瞬时态(transient)托管态(persistent)游离态(detached)移除态(removed)注意:这里最后一个移除态,有的时候也叫删除态(deleted),至于它和移除态有啥区别,暂时没有想到,如果您对此有更加深刻的理解,请留言回复。为什么会有这四种状态呢?啥,这个也有为啥,网上不是都这么说的

JPA实体状态学习-(瞬时态:Transient)

为了学习实体的状态,我们还是贴出这张实体状态转换迁移图:Transient(瞬时态)按照上图的描述,java对象在内存中被赋值后,没有调用entityManager.persist()方法之前实体对象所处的状态就是瞬時態举个例子:Teacher teacher = new Teacher("email@dot.com");此时,实例teacher就处于new/transient态(备注:这里的ne

JPA实体状态学习-(游离态:Detached)

今天我们学习另一种实体状态,老规矩还是先上图:Detached(游离态 unmanaged)An Object becomes detached when the currently running Persistence Context is closed. Any changes made to detached objects are no longer automatically prop

JPA实体映射——Entity Mapping

学习JPA,实体之间的映射关系是最重要的一环,为了学习和讨论这部分知识,我们将这部分知识分为若干章节进行学习,我们也会用实际的例子进行分析,并且指出存在的问题,然后给出相应的优化方案。 第一步,我们列出具体的案例我们分别使用了三个实体:Institute(研究所),Department(部门),SocialProfile(社交账号)。如上图所示,研究所和部门是一对多的关系,研究所和社交账