今天我们学习另一种实体状态,老规矩还是先上图:
Detached(游离态 unmanaged)
An Object becomes detached when the currently running Persistence Context is closed. Any changes made to detached objects are no longer automatically propagated to the database.
持久化上下文关闭以后,对象就会进入游离态。任何对游离态对象的改变都不会自动持久化到数据库。
这个现象我们在上一讲已经用代码证明过,现在的问题是,由上面的图片可以看出,处于游离态的对象可以通过merge方法变成收到持久化上下文管理的持久态。我们还是用代码来说明:
public void detachedToPersist() {
Teacher teacher = new Teacher("new_email@gmail.com");
logger.info("teacher: {} is transient state",teacher);
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction tx = entityManager.getTransaction();
tx.begin();
entityManager.persist(teacher);
logger.info("teacher: {} is persistent state",teacher);
Long persistedId = teacher.getId();
tx.commit();
entityManager.close();
teacher.setEmail("update_email@gmail.com");
logger.info("teacher: {} is detached state",teacher);
entityManager = entityManagerFactory.createEntityManager();
tx = entityManager.getTransaction();
tx.begin();
Teacher newTeacher = entityManager.merge(teacher);
logger.info("teacher: {} is persistent state",teacher);
persistedId = newTeacher.getId();
tx.commit();
entityManager.close();
entityManager = entityManagerFactory.createEntityManager();
tx = entityManager.getTransaction();
tx.begin();
teacher = entityManager.find(Teacher.class, persistedId);
tx.commit();
entityManager.close();
logger.info("merge() execute ,Persisted teacher: {}", teacher);
}
teacher: Student{id=null, email='new_email@gmail.com'} is transient state
Hibernate:
call next value for hibernate_sequence
teacher: Student{id=1, email='new_email@gmail.com'} is persistent state
Hibernate:
insert
into
teachers
(email, id)
values
(?, ?)
teacher: Student{id=1, email='update_email@gmail.com'} is detached state
Hibernate:
select
teacher0_.id as id1_0_0_,
teacher0_.email as email2_0_0_
from
teachers teacher0_
where
teacher0_.id=?
teacher: Student{id=1, email='update_email@gmail.com'} is persistent state
Hibernate:
update
teachers
set
email=?
where
id=?
Hibernate:
select
teacher0_.id as id1_0_0_,
teacher0_.email as email2_0_0_
from
teachers teacher0_
where
teacher0_.id=?
merge() execute ,Persisted teacher: Student{id=1, email='update_email@gmail.com'}
通过上面的代码可以知道,当一个对象进入detached状态后,可以通过merge方法让对象再次进入持久化的状态,如果detached状态的对象在数据库中存在,此时如果此对象的状态有改变,那么调用merge方法的时候,会先查询出来这条数据,然后执行更新语句。
用我们的例子来说就是teacher对象通过persist()方法存入数据库后,此时这个对象是包含一个id的,及时处于游离态,它也包含这个id,如果不对这个对象更改,直接调用merge()的话,此时只会发出查询语句;如果改变对象,则发出更新语句。我这里是验证了改变对象的情况,有兴趣的可以试试不改变的情况。