JPA实体状态学习-(瞬时态:Transient)

时间:2022-06-01 21:20:25
JPA实体状态学习-(瞬时态:Transient)

为了学习实体的状态,我们还是贴出这张实体状态转换迁移图:

Transient(瞬时态)

按照上图的描述,java对象在内存中被赋值后,没有调用entityManager.persist()方法之前实体对象所处的状态。

举个例子:

Teacher teacher = new Teacher("email@dot.com");

此时,实例teacher就处于new/transient态(备注:这里的new和transient是同一个意思

 

Persistent(持久态)

掌握这个状态,需要记住一句关键的话:

An Object that is associated with persistence context (hibernate session) are in Persistent state. Any changes made to objects in this state are automatically propagated to databases without manually invoking persist/merge/remove

与持久上下文关联的对象处于持久态。任何对这个对象属性的更改都会自动传播到数据库而不需手动调用persist/merge/remove方法。(备注:这里的关联的意思就是说实体对象被持久上下文管理,也有的翻译将这个状态称作托管态)

代码举例:

这里我们还是用代码来说明:

**
 * 测试保存,验证持久态的数据更新
 */
public void saveTeacher() {
    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);
    teacher.setEmail("updated_email@gmail.com");
    Long persistedId = teacher.getId();
    logger.info("teacher: {} has changed email",teacher);
    tx.commit();
    entityManager.close();
    logger.info("teacher: {} is detached state",teacher);
    entityManager = entityManagerFactory.createEntityManager();
    tx = entityManager.getTransaction();
    tx.begin();
    teacher = entityManager.find(Teacher.class, persistedId);
    tx.commit();
    entityManager.close();
    logger.info("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
teacher: Student{id=1, email='updated_email@gmail.com'} has changed email
Hibernate: 
   insert 
   into
       teachers
       (email, id) 
   values
       (?, ?)
Hibernate: 
   update
       teachers 
   set
       email=? 
   where
       id=?
teacher: Student{id=1, email='updated_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=?
Persisted teacher: Student{id=1, email='updated_email@gmail.com'}

日志分析:

以上的日志说明了一个teacher对象从transient----->persistent----->detached 过程中,SQL语句的执行情况:

执行persist()到持久态后执行一条insertSQL语句;

当改变持久态对象的属性时会执行一条update语句,这两条语句显然都是tx.commit()后才发出;

最后发出一个select语句来查询数据库中最终的teacher对象,用于验证之前的结论。

管理这一过程的就是持久化上下文。

我们测试在detached态时修改对象的状态有啥不一样:

/**
 * 测试保存,验证持久态的数据更新
 */
public void saveTeacher() {
    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);
    teacher.setEmail("updated_email@gmail.com");
    Long persistedId = teacher.getId();
    logger.info("teacher: {} has changed email",teacher);
    tx.commit();
    //增加了这一行代码后
    teacher.setEmail("updated_email1@gmail.com");
    entityManager.close();
    logger.info("teacher: {} is detached state",teacher);
    entityManager = entityManagerFactory.createEntityManager();
    tx = entityManager.getTransaction();
    tx.begin();
    teacher = entityManager.find(Teacher.class, persistedId);
    tx.commit();
    entityManager.close();
    logger.info("Persisted teacher: {}", teacher);
}

这里我只截取部分输出,能够看到结果表明原理就好

teacher: Student{id=1, email='updated_email1@gmail.com'} is detached state

Persisted teacher: Student{id=1, email='updated_email@gmail.com'}

可以知道,detached状态的对象属性email已经改变成updated_email1@gmail.com,但是从数据库查询数来的值没有改变,还是updated_email@gmail.com

结论说明

  • Detached状态的实体属性改变不会同步更新数据库
  • Persistent状态的实体属性改变会同步更新数据库

下一篇,我会尝试用代码来说明其他实体状态的迁移,欢迎大家多多分享和交流。