Reattaching detached data
Session.lock
package org.example.demo.hibernate;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.service.ServiceRegistry;
public class Test {
public static void main(String[] args) {
ServiceRegistry standardRegistry = new StandardServiceRegistryBuilder()
.applySetting("hibernate.connection.url", "jdbc:p6spy:postgresql://localhost:5432/test")
.applySetting("hibernate.connection.username", "postgres")
.applySetting("hibernate.connection.password", "postgres")
.applySetting("hibernate.hbm2ddl.auto", "create").build();
Metadata metadata = new MetadataSources(standardRegistry).addAnnotatedClass(Person.class).getMetadataBuilder()
.applyImplicitNamingStrategy(ImplicitNamingStrategyJpaCompliantImpl.INSTANCE).build();
SessionFactory sessionFactory = metadata.getSessionFactoryBuilder().build();
Session session = sessionFactory.openSession();
session.beginTransaction();
Person person = new Person();
person.name = "john doe";
session.persist(person);
session.getTransaction().commit();
session.clear();
Person p = session.get(Person.class, person.id);
session.clear();
session.beginTransaction();
session.lock(p, LockMode.NONE);
p.name = "Mr. John Doe";
session.getTransaction().commit();
session.close();
sessionFactory.close();
}
@Entity(name = "Person")
public static class Person {
@Id
@GeneratedValue
Integer id;
String name;
}
}
生成的 SQL
drop table if exists Person 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))
select nextval ('hibernate_sequence')
insert into Person (name, id) values ('john doe', 1)
select test_perso0_.id as id1_0_0_, test_perso0_.name as name2_0_0_ from Person test_perso0_ where test_perso0_.id=1
update Person set name='Mr. John Doe' where id=1
注意:
- 如果第 40 行和第 41 行颠倒,即先
p.name = "Mr. John Doe";
再session.lock(p, LockMode.NONE);
则不会生成 update 语句 - 如果注掉第 39 行和第 42 行,即不在事务中,也不会生成 update 语句,也不报错。
Session.saveOrUpdate
package org.example.demo.hibernate;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.service.ServiceRegistry;
public class Test {
public static void main(String[] args) {
ServiceRegistry standardRegistry = new StandardServiceRegistryBuilder()
.applySetting("hibernate.connection.url", "jdbc:p6spy:postgresql://localhost:5432/test")
.applySetting("hibernate.connection.username", "postgres")
.applySetting("hibernate.connection.password", "postgres")
.applySetting("hibernate.hbm2ddl.auto", "create").build();
Metadata metadata = new MetadataSources(standardRegistry).addAnnotatedClass(Person.class).getMetadataBuilder()
.applyImplicitNamingStrategy(ImplicitNamingStrategyJpaCompliantImpl.INSTANCE).build();
SessionFactory sessionFactory = metadata.getSessionFactoryBuilder().build();
Session session = sessionFactory.openSession();
session.beginTransaction();
Person person = new Person();
person.name = "john doe";
session.persist(person);
session.getTransaction().commit();
session.clear();
Person p = session.get(Person.class, person.id);
session.clear();
session.beginTransaction();
p.name = "Mr. John Doe";
session.saveOrUpdate(p);
session.getTransaction().commit();
session.close();
sessionFactory.close();
}
@Entity(name = "Person")
public static class Person {
@Id
@GeneratedValue
Integer id;
String name;
}
}
生成的 SQL
drop table if exists Person 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))
select nextval ('hibernate_sequence')
insert into Person (name, id) values ('john doe', 1)
select test_perso0_.id as id1_0_0_, test_perso0_.name as name2_0_0_ from Person test_perso0_ where test_perso0_.id=1
update Person set name='Mr. John Doe' where id=1
注意
- 这时第 39 行
p.name = "Mr. John Doe";
和第 40 行session.saveOrUpdate(p);
的顺序无所谓 - 仍然需要第 38 行和第 41 行的事务,否则不会生成 update 语句,也不报错
Merging detached data
EntityManager.merge
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>
package org.example.demo.hibernate;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Persistence;
public class Test {
public static void main(String[] args) {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
EntityManager em = factory.createEntityManager();
em.getTransaction().begin();
Person person = new Person();
person.name = "john doe";
em.persist(person);
em.getTransaction().commit();
em.clear();
Person p = em.find(Person.class, person.id);
em.clear();
p.name = "Mr. John Doe";
em.getTransaction().begin();
p = em.merge(p);
em.getTransaction().commit();
em.close();
factory.close();
}
@Entity(name = "Person")
public static class Person {
@Id
@GeneratedValue
Integer id;
String name;
}
}
生成的 SQL
drop table if exists Person 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))
select nextval ('hibernate_sequence')
insert into Person (name, id) values ('john doe', 1)
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 test_perso0_.id as id1_0_0_, test_perso0_.name as name2_0_0_ from Person test_perso0_ where test_perso0_.id=1
update Person set name='Mr. John Doe' where id=1
注意:
- 如果没有第 28 行和第 30 行的事务,则不会生成 update 语句,也不报错
Session.merge
package org.example.demo.hibernate;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.service.ServiceRegistry;
public class Test {
public static void main(String[] args) {
ServiceRegistry standardRegistry = new StandardServiceRegistryBuilder()
.applySetting("hibernate.connection.url", "jdbc:p6spy:postgresql://localhost:5432/test")
.applySetting("hibernate.connection.username", "postgres")
.applySetting("hibernate.connection.password", "postgres")
.applySetting("hibernate.hbm2ddl.auto", "create").build();
Metadata metadata = new MetadataSources(standardRegistry).addAnnotatedClass(Person.class).getMetadataBuilder()
.applyImplicitNamingStrategy(ImplicitNamingStrategyJpaCompliantImpl.INSTANCE).build();
SessionFactory sessionFactory = metadata.getSessionFactoryBuilder().build();
Session session = sessionFactory.openSession();
session.beginTransaction();
Person person = new Person();
person.name = "john doe";
session.persist(person);
session.getTransaction().commit();
session.clear();
Person p = session.get(Person.class, person.id);
session.clear();
session.beginTransaction();
p.name = "Mr. John Doe";
session.merge(p);
session.getTransaction().commit();
session.close();
sessionFactory.close();
}
@Entity(name = "Person")
public static class Person {
@Id
@GeneratedValue
Integer id;
String name;
}
}
生成的 SQL
drop table if exists Person 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))
select nextval ('hibernate_sequence')
insert into Person (name, id) values ('john doe', 1)
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 test_perso0_.id as id1_0_0_, test_perso0_.name as name2_0_0_ from Person test_perso0_ where test_perso0_.id=1
update Person set name='Mr. John Doe' where id=1
注意
- 如果没有第 38 行和第 41 行的事务,则将不会生成 update 语句,也不报错。
Merging gotchas
FIXME