1. 暂存区
Hibernate 实体的生命周期与持久性的上下文有关。
持久性的上下文(Session
)处于客户端代码与数据存储之间,它类似于暂存区,负责客户端与数据库的交互。
在暂存区的内所有数据的更改都会被跟踪,并在业务结束时将更改同步至数据库
2. 生命周期概览
3. 瞬态
瞬态只是一个实体对象(DO,PO类的实例),它不存在于
暂存区
中。
不存在于暂存区的对象是不会被跟踪的,所以对瞬态的任何操作都不会影响至数据库!
要使瞬态持久化则需要调用生命周期中的方法:save()
,persist()
,saveOrUpdate()
。
3.1 persist()
persist() 符合JPA规范
调用 persist()
后,对象就会从瞬态
转换为持久态
,该对象处于暂存区中,但尚未保存到数据库中。因为只有在提交事务,刷新或关闭会话时才会生成 insert
语句。
persist()
方法返回 void
类型
使用细节:
- 如果对一个
已持久化
的对象继续调用persist()
则对这个实例没有任何影响 - 如果对一个处于
分离
状态的对象调用persist()
时,提交或刷新会话时得到一个异常
Person person = new Person();
person.setName("John");
session.persist(person);
session.evict(person);
session.persist(person); // PersistenceException!
3.1 save()
save() 方法不符合JPA规范
与 persist()
方法基本一致,不过此方法首先分配生成的标识符,然后返回此标识符的序列值。
Person person = new Person();
person.setName("John");
Long id = (Long) session.save(person);
当尝试保存一个 分离
的实例时,区别就此诞生
Person person = new Person();
person.setName("John");
Long id1 = (Long) session.save(person); // 分配一个新标识符
session.evict(person);
Long id2 = (Long) session.save(person); // 分配一个新标识符
对 分离
实例的保存调用会创建一个新的持久实例并为其分配一个新标识符
3.1 saveOrUpdate()
saveOrUpdate() 方法不符合JPA规范
saveOrUpdate()
方法的主要区别在于它在应用于 瞬态
实例时不会抛出异常,而是使这个瞬态实例持久化。
Person person = new Person();
person.setName("John");
session.saveOrUpdate(person);
可以将此方法视为一种通用工具,用于使对象持久化,而不管其状态如何,无论是瞬态的还是分离的
4. 持久性
处在
持久性
状态的实例相当于处在暂存区
中,对它的所有更改都会传播到数据库
要使处在 瞬态
状态的实例转换至 持久
性状态提供了几种方法:lock()
,update()
,merge()
,saveOrUpdate()
4.1 lock()
lock() 符合JPA规范
lock() 将 分离
实体重新附加至暂存区
4.2 update()
update() 不符合JPA规范
update()
方法将传递的对象从 分离
状态转换为 持久
状态
将 瞬态
实体传递给此方法,则会引发异常
Person person = new Person();
person.setName("John");
session.update(person); // PersistenceException!
4.2 merge()
merge() 符合JPA规范
merge() 细节:
- 通过从传递的对象获取的 id 查找实体实例(检索持久性上下文中的现有实体实例,或从数据库加载的新实例)
- 将字段从传递的对象复制到此实例
- 返回一个新更新的实例
Person person = new Person();
person.setName("John");
session.save(person);
session.evict(person);
person.setName("Mary");
Person mergedPerson = (Person) session.merge(person);