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

时间:2022-06-01 21:21:31

今天我们学习另一种实体状态,老规矩还是先上图:

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 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()的话,此时只会发出查询语句;如果改变对象,则发出更新语句。我这里是验证了改变对象的情况,有兴趣的可以试试不改变的情况。