CascadeType 参见 org.hibernate.annotations.CascadeType

src/main/resources/META-INF/persistence.xml

<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
             http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
  version="2.1">
  <persistence-unit name="test">
    <properties>
      <property name="javax.persistence.jdbc.url" value="jdbc:p6spy:postgresql://localhost:5432/test" />
      <property name="javax.persistence.jdbc.user" value="postgres" />
      <property name="javax.persistence.jdbc.password" value="postgres" />

      <property name="javax.persistence.schema-generation.database.action" value="drop-and-create" />
    </properties>
  </persistence-unit>
</persistence>

CascadeType.PERSIST

package org.example.demo.hibernate;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Persistence;

public class Test {
    public static void main(String[] args) {
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
        EntityManager em = factory.createEntityManager();

        Person person = new Person();
        person.name = "john doe";

        Phone phone = new Phone();
        phone.number = "123-456-7890";

        person.phones.add(phone);
        phone.owner = person;

        em.getTransaction().begin();
        em.persist(person);
        em.getTransaction().commit();

        em.close();
        factory.close();
    }

    @Entity(name = "Person")
    public static class Person {
        @Id
        @GeneratedValue
        Integer id;
        String name;
        @OneToMany(mappedBy = "owner", cascade = CascadeType.PERSIST)
        List<Phone> phones = new ArrayList<>();
    }

    @Entity(name = "Phone")
    public static class Phone {
        @Id
        @GeneratedValue
        private Long id;
        @Column(name = "`number`")
        private String number;
        @ManyToOne(fetch = FetchType.LAZY)
        private Person owner;
    }
}

生成的 SQL

alter table Phone drop constraint FK82m836qc1ss2niru7eogfndhl
drop table if exists Person cascade
drop table if exists Phone cascade
drop sequence if exists hibernate_sequence

create sequence hibernate_sequence start 1 increment 1
create table Person (id int4 not null, name varchar(255), primary key (id))
create table Phone (id int8 not null, "number" varchar(255), owner_id int4, primary key (id))
alter table Phone add constraint FK82m836qc1ss2niru7eogfndhl foreign key (owner_id) references Person
select nextval ('hibernate_sequence')
select nextval ('hibernate_sequence')
insert into Person (name, id) values ('john doe', 1)
insert into Phone ("number", owner_id, id) values ('123-456-7890', 1, 2)

CascadeType.MERGE

package org.example.demo.hibernate;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Persistence;

public class Test {
    public static void main(String[] args) {
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
        EntityManager em = factory.createEntityManager();

        Person person = new Person();
        person.name = "john doe";

        Phone phone = new Phone();
        phone.number = "123-456-7890";

        person.phones.add(phone);
        phone.owner = person;

        em.getTransaction().begin();
        em.persist(person);
        em.persist(phone);
        em.getTransaction().commit();

        em.clear();

        Phone ph = em.find(Phone.class, phone.id);
        Person pe = ph.owner;
        pe.setName("John Doe Jr.");
        // [org.example.demo.hibernate.Test$Phone@367795c7]
        System.out.println(pe.getPhones());
        ph.number = "987-654-3210";

        em.clear();

        em.getTransaction().begin();
        em.merge(pe);
        em.getTransaction().commit();

        em.close();
        factory.close();
    }

    @Entity(name = "Person")
    public static class Person {
        @Id
        @GeneratedValue
        Long id;
        String name;
        @OneToMany(mappedBy = "owner", cascade = CascadeType.MERGE)
        List<Phone> phones = new ArrayList<>();

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public List<Phone> getPhones() {
            return phones;
        }

        public void setPhones(List<Phone> phones) {
            this.phones = phones;
        }
    }

    @Entity(name = "Phone")
    public static class Phone {
        @Id
        @GeneratedValue
        Long id;
        @Column(name = "`number`")
        String number;
        @ManyToOne(fetch = FetchType.LAZY)
        Person owner;
    }
}

生成的 SQL

alter table Phone drop constraint FK82m836qc1ss2niru7eogfndhl
drop table if exists Person cascade
drop table if exists Phone cascade
drop sequence if exists hibernate_sequence

create sequence hibernate_sequence start 1 increment 1
create table Person (id int8 not null, name varchar(255), primary key (id))
create table Phone (id int8 not null, "number" varchar(255), owner_id int8, primary key (id))
alter table Phone add constraint FK82m836qc1ss2niru7eogfndhl foreign key (owner_id) references Person
select nextval ('hibernate_sequence')
select nextval ('hibernate_sequence')
insert into Person (name, id) values ('john doe', 1)
insert into Phone ("number", owner_id, id) values ('123-456-7890', 1, 2)

select test_phone0_.id as id1_1_0_, test_phone0_."number" as number2_1_0_, test_phone0_.owner_id as owner_id3_1_0_ from Phone test_phone0_ where test_phone0_.id=2
select test_perso0_.id as id1_0_0_, test_perso0_.name as name2_0_0_ from Person test_perso0_ where test_perso0_.id=1
select phones0_.owner_id as owner_id3_1_0_, phones0_.id as id1_1_0_, phones0_.id as id1_1_1_, phones0_."number" as number2_1_1_, phones0_.owner_id as owner_id3_1_1_ from Phone phones0_ where phones0_.owner_id=1
select test_perso0_.id as id1_0_1_, test_perso0_.name as name2_0_1_, phones1_.owner_id as owner_id3_1_3_, phones1_.id as id1_1_3_, phones1_.id as id1_1_0_, phones1_."number" as number2_1_0_, phones1_.owner_id as owner_id3_1_0_ from Person test_perso0_ left outer join Phone phones1_ on test_perso0_.id=phones1_.owner_id where test_perso0_.id=1
update Phone set "number"='987-654-3210', owner_id=1 where id=2
update Person set name='John Doe Jr.' where id=1

注意:

  • 第 41 行 pe.setName("John Doe Jr."); 如果改成 pe.name = "John Doe Jr."; 则不会生成 update Person 语句(仍有 update Phone 语句),因为 pe 是 runtime proxy
  • 如果注掉第 43 行 System.out.println(pe.getPhones()); ,则不会生成第 3 条 select 语句也不会 update Phone ,因为 pe.phones 是 runtime proxy 尚未加载(Persistence.getPersistenceUtil().isLoaded(pe.getPhones() = false)
  • 注意第 4 条 select 语句,因为 CascadeType.MERGE 所以连同 Phone 一同 select 出来,然后 merge 。即使注掉第 43, 44 行,也会生成同样的 select 语句。

CascadeType.REMOVE

package org.example.demo.hibernate;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Persistence;

public class Test {
    public static void main(String[] args) {
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
        EntityManager em = factory.createEntityManager();

        Person person = new Person();
        person.name = "john doe";

        Phone phone = new Phone();
        phone.number = "123-456-7890";

        person.phones.add(phone);
        phone.owner = person;

        em.getTransaction().begin();
        em.persist(person);
        em.persist(phone);
        em.getTransaction().commit();

        em.clear();

        Person pe = em.find(Person.class, person.id);

        em.getTransaction().begin();
        em.remove(pe);
        em.getTransaction().commit();

        em.close();
        factory.close();
    }

    @Entity(name = "Person")
    public static class Person {
        @Id
        @GeneratedValue
        Long id;
        String name;
        @OneToMany(mappedBy = "owner", cascade = CascadeType.REMOVE)
        List<Phone> phones = new ArrayList<>();
    }

    @Entity(name = "Phone")
    public static class Phone {
        @Id
        @GeneratedValue
        Long id;
        @Column(name = "`number`")
        String number;
        @ManyToOne(fetch = FetchType.LAZY)
        Person owner;
    }
}

生成的 SQL

alter table Phone drop constraint FK82m836qc1ss2niru7eogfndhl
drop table if exists Person cascade
drop table if exists Phone cascade
drop sequence if exists hibernate_sequence

create sequence hibernate_sequence start 1 increment 1
create table Person (id int8 not null, name varchar(255), primary key (id))
create table Phone (id int8 not null, "number" varchar(255), owner_id int8, primary key (id))
alter table Phone add constraint FK82m836qc1ss2niru7eogfndhl foreign key (owner_id) references Person
select nextval ('hibernate_sequence')
select nextval ('hibernate_sequence')
insert into Person (name, id) values ('john doe', 1)
insert into Phone ("number", owner_id, id) values ('123-456-7890', 1, 2)

select test_perso0_.id as id1_0_0_, test_perso0_.name as name2_0_0_ from Person test_perso0_ where test_perso0_.id=1
select phones0_.owner_id as owner_id3_1_0_, phones0_.id as id1_1_0_, phones0_.id as id1_1_1_, phones0_."number" as number2_1_1_, phones0_.owner_id as owner_id3_1_1_ from Phone phones0_ where phones0_.owner_id=1
delete from Phone where id=2
delete from Person where id=1

CascadeType.DETACH

package org.example.demo.hibernate;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Persistence;

public class Test {
    public static void main(String[] args) {
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
        EntityManager em = factory.createEntityManager();

        Person person = new Person();
        person.name = "john doe";

        Phone phone = new Phone();
        phone.number = "123-456-7890";

        person.phones.add(phone);
        phone.owner = person;

        em.getTransaction().begin();
        em.persist(person);
        em.persist(phone);
        em.getTransaction().commit();

        em.clear();

        Person pe = em.find(Person.class, person.id);
        Phone ph = pe.phones.get(0);

        // true
        System.out.println(em.contains(pe));
        // true
        System.out.println(em.contains(ph));

        em.detach(pe);
        // false
        System.out.println(em.contains(pe));
        // false
        System.out.println(em.contains(ph));

        em.close();
        factory.close();
    }

    @Entity(name = "Person")
    public static class Person {
        @Id
        @GeneratedValue
        Long id;
        String name;
        @OneToMany(mappedBy = "owner", cascade = CascadeType.DETACH)
        List<Phone> phones = new ArrayList<>();
    }

    @Entity(name = "Phone")
    public static class Phone {
        @Id
        @GeneratedValue
        Long id;
        @Column(name = "`number`")
        String number;
        @ManyToOne(fetch = FetchType.LAZY)
        Person owner;
    }
}

CascadeType.LOCK

package org.example.demo.hibernate;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Persistence;

import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;

public class Test {
    public static void main(String[] args) {
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
        EntityManager em = factory.createEntityManager();

        Person person = new Person();
        person.name = "john doe";

        Phone phone = new Phone();
        phone.number = "123-456-7890";

        person.phones.add(phone);
        phone.owner = person;

        em.getTransaction().begin();
        em.persist(person);
        em.persist(phone);
        em.getTransaction().commit();

        em.clear();

        Person pe = em.find(Person.class, person.id);
        Phone ph = pe.phones.get(0);

        // true
        System.out.println(em.contains(pe));
        // true
        System.out.println(em.contains(ph));

        em.clear();
        // false
        System.out.println(em.contains(pe));
        // false
        System.out.println(em.contains(ph));

        em.unwrap(Session.class).lock(pe, LockMode.NONE);
        // true
        System.out.println(em.contains(pe));
        // true
        System.out.println(em.contains(ph));

        em.getTransaction().begin();
        ph.number = "987-654-3210";
        em.getTransaction().commit();

        em.close();
        factory.close();
    }

    @Entity(name = "Person")
    public static class Person {
        @Id
        @GeneratedValue
        Long id;
        String name;
        @OneToMany(mappedBy = "owner")
        @Cascade(CascadeType.LOCK)
        List<Phone> phones = new ArrayList<>();
    }

    @Entity(name = "Phone")
    public static class Phone {
        @Id
        @GeneratedValue
        Long id;
        @Column(name = "`number`")
        String number;
        @ManyToOne(fetch = FetchType.LAZY)
        Person owner;
    }
}

生成的 SQL

alter table Phone drop constraint FK82m836qc1ss2niru7eogfndhl
drop table if exists Person cascade
drop table if exists Phone cascade
drop sequence if exists hibernate_sequence

create sequence hibernate_sequence start 1 increment 1
create table Person (id int8 not null, name varchar(255), primary key (id))
create table Phone (id int8 not null, "number" varchar(255), owner_id int8, primary key (id))
alter table Phone add constraint FK82m836qc1ss2niru7eogfndhl foreign key (owner_id) references Person
select nextval ('hibernate_sequence')
select nextval ('hibernate_sequence')
insert into Person (name, id) values ('john doe', 1)
insert into Phone ("number", owner_id, id) values ('123-456-7890', 1, 2)

select test_perso0_.id as id1_0_0_, test_perso0_.name as name2_0_0_ from Person test_perso0_ where test_perso0_.id=1
select phones0_.owner_id as owner_id3_1_0_, phones0_.id as id1_1_0_, phones0_.id as id1_1_1_, phones0_."number" as number2_1_1_, phones0_.owner_id as owner_id3_1_1_ from Phone phones0_ where phones0_.owner_id=1
update Phone set "number"='987-654-3210', owner_id=1 where id=2

CascadeType.REFRESH

package org.example.demo.hibernate;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Persistence;

public class Test {
    public static void main(String[] args) {
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
        EntityManager em = factory.createEntityManager();

        Person person = new Person();
        person.name = "john doe";

        Phone phone = new Phone();
        phone.number = "123-456-7890";

        person.phones.add(phone);
        phone.owner = person;

        em.getTransaction().begin();
        em.persist(person);
        em.persist(phone);
        em.getTransaction().commit();

        em.clear();

        Person pe = em.find(Person.class, person.id);
        Phone ph = pe.phones.get(0);
        pe.name = "John Doe Jr.";
        ph.number = "987-654-3210";

        em.refresh(pe);
        // john doe
        System.out.println(pe.name);
        // 123-456-7890
        System.out.println(ph.number);

        em.close();
        factory.close();
    }

    @Entity(name = "Person")
    public static class Person {
        @Id
        @GeneratedValue
        Long id;
        String name;
        @OneToMany(mappedBy = "owner", cascade = CascadeType.REFRESH)
        List<Phone> phones = new ArrayList<>();
    }

    @Entity(name = "Phone")
    public static class Phone {
        @Id
        @GeneratedValue
        Long id;
        @Column(name = "`number`")
        String number;
        @ManyToOne(fetch = FetchType.LAZY)
        Person owner;
    }
}

生成的 SQL

alter table Phone drop constraint FK82m836qc1ss2niru7eogfndhl
drop table if exists Person cascade
drop table if exists Phone cascade
drop sequence if exists hibernate_sequence

create sequence hibernate_sequence start 1 increment 1
create table Person (id int8 not null, name varchar(255), primary key (id))
create table Phone (id int8 not null, "number" varchar(255), owner_id int8, primary key (id))
alter table Phone add constraint FK82m836qc1ss2niru7eogfndhl foreign key (owner_id) references Person
select nextval ('hibernate_sequence')
select nextval ('hibernate_sequence')
insert into Person (name, id) values ('john doe', 1)
insert into Phone ("number", owner_id, id) values ('123-456-7890', 1, 2)

select test_perso0_.id as id1_0_0_, test_perso0_.name as name2_0_0_ from Person test_perso0_ where test_perso0_.id=1
select phones0_.owner_id as owner_id3_1_0_, phones0_.id as id1_1_0_, phones0_.id as id1_1_1_, phones0_."number" as number2_1_1_, phones0_.owner_id as owner_id3_1_1_ from Phone phones0_ where phones0_.owner_id=1
select test_phone0_.id as id1_1_0_, test_phone0_."number" as number2_1_0_, test_phone0_.owner_id as owner_id3_1_0_ from Phone test_phone0_ where test_phone0_.id=2
select test_perso0_.id as id1_0_1_, test_perso0_.name as name2_0_1_, phones1_.owner_id as owner_id3_1_3_, phones1_.id as id1_1_3_, phones1_.id as id1_1_0_, phones1_."number" as number2_1_0_, phones1_.owner_id as owner_id3_1_0_ from Person test_perso0_ left outer join Phone phones1_ on test_perso0_.id=phones1_.owner_id where test_perso0_.id=1

CascadeType.REPLICATE

package org.example.demo.hibernate;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Persistence;

import org.hibernate.ReplicationMode;
import org.hibernate.Session;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;

public class Test {
    public static void main(String[] args) {
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
        EntityManager em = factory.createEntityManager();

        Person person = new Person();
        person.name = "john doe";

        Phone phone = new Phone();
        phone.number = "123-456-7890";

        person.phones.add(phone);
        phone.owner = person;

        em.getTransaction().begin();
        em.persist(person);
        em.persist(phone);
        em.getTransaction().commit();

        em.clear();

        Person pe = new Person();
        pe.id = person.id;
        pe.name = "John Doe Sr.";

        Phone ph = new Phone();
        ph.id = phone.id;
        ph.number = "987-654-3210";

        pe.phones.add(ph);
        ph.owner = pe;

        em.getTransaction().begin();
        em.unwrap(Session.class).replicate(pe, ReplicationMode.OVERWRITE);
        em.getTransaction().commit();

        em.close();
        factory.close();
    }

    @Entity(name = "Person")
    public static class Person {
        @Id
        @GeneratedValue
        Long id;
        String name;
        @OneToMany(mappedBy = "owner")
        @Cascade(CascadeType.REPLICATE)
        List<Phone> phones = new ArrayList<>();
    }

    @Entity(name = "Phone")
    public static class Phone {
        @Id
        @GeneratedValue
        Long id;
        @Column(name = "`number`")
        String number;
        @ManyToOne(fetch = FetchType.LAZY)
        Person owner;
    }
}

生成的 SQL

alter table Phone drop constraint FK82m836qc1ss2niru7eogfndhl
drop table if exists Person cascade
drop table if exists Phone cascade
drop sequence if exists hibernate_sequence

create sequence hibernate_sequence start 1 increment 1
create table Person (id int8 not null, name varchar(255), primary key (id))
create table Phone (id int8 not null, "number" varchar(255), owner_id int8, primary key (id))
alter table Phone add constraint FK82m836qc1ss2niru7eogfndhl foreign key (owner_id) references Person
select nextval ('hibernate_sequence')
select nextval ('hibernate_sequence')
insert into Person (name, id) values ('john doe', 1)
insert into Phone ("number", owner_id, id) values ('123-456-7890', 1, 2)

select id from Person where id =1
select id from Phone where id =2
update Person set name='John Doe Sr.' where id=1
update Phone set "number"='987-654-3210', owner_id=1 where id=2

results matching ""

    No results matching ""