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