为了学习实体的状态,我们还是贴出这张实体状态转换迁移图:
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状态的实体属性改变会同步更新数据库
下一篇,我会尝试用代码来说明其他实体状态的迁移,欢迎大家多多分享和交流。