站在持久化的角度,Hibernate把对象分为了4种状态:持久化状态,临时状态,游离状态和删除状态。Session的特定方法能使对象从一个状态转换到另一个状态。
- 临时对象(Transient):
在使用代理主键的情况下,OID 通常为 null;
不处于Session的缓存中;
在数据库中没有对应的记录。
通常使用new创建一个新的对象,并且不设置它的id属性值,则这个对象就是临时对象。 - 持久化对象 (也叫“托管”)(Persist):
OID不为null;
位于Session缓存中;
若在数据库中已经有和其对应的记录,则持久化对象和数据库中的相关记录对应;
Session在flush缓存时,会根据持久化对象的属性变化,来同步更新数据库;
在同一个Session实例的缓存中,数据库表中的每条记录只对应唯一的持久化对象。 - 游离对象 (也叫”脱管”) (Detached):
OID不为null;
不再处于Session缓存中;
一般情况需下,游离对象是由持久化对象转变过来的,因此在数据库中可能还存在与它对应的记录。 删除对象 (Removed):
在数据库中没有和其OID对应的记录;
不再处于Session 缓存中;
一般情况下,应用程序不该再使用被删除的对象。这几种状态的对象转换图如下:
下面介绍Session能够转换对象状态的方法:save()
Session 的 save() 方法使一个临时对象转变为持久化对象;
Session 的 save() 方法完成以下操作:
1. 把 News 对象加入到 Session 缓存中,使它进入持久化状态;
2. 选用映射文件指定的标识符生成器, 为持久化对象分配唯一的 OID。
(在使用代理主键的情况下, setId() 方法为 News 对象设置 OID 是无效的)
3. 计划执行一条 insert 语句:在 flush 缓存的时候,hibernate 通过持久化对象的 OID 来维持它和数据库相关记录的对应关系,当 News 对象处于持久化状态时, 不允许程序随意修改它的 ID。
persist() 和 save() 区别:
当对一个OID不为Null的对象执行save()方法时,会把该对象以一个新的OID保存到数据库中; 但执行persist()方法时会抛出一个异常。get() 和 load()
1. 这两个方法都可以根据给定的 OID 从数据库中加载一个持久化对象;
2. 执行 get 方法: 会立即加载对象;(立即检索)
执行 load 方法:若不使用该对象,则不会立即执行查询操作,而返回一个代理对象,直到使用到该对象的时候才会加载。(延迟检索)
3. 如果在需要初始化代理对象之前已经关闭了session,load方法可能会抛出 LazyInitializationException 异常(懒加载异常)。例如:下面这段代码会抛出懒加载异常:
public void testLoad(){
News news = (News) session.load(News.class, 1);
session.close();
System.out.println(news);
}
而下面这段代码则可以正常加载:
public void testLoad(){
News news = (News) session.load(News.class, 1);
System.out.println(news);
session.close();
System.out.println(news);
}
4. 若数据表中不存在与OID对应的记录,且Session也没有被关闭:
get方法会返回null;
load方法若不使用该对象的任何属性,则不会出现问题;否则将抛出ObjectNotFoundException异常。
update()
1. Session 的update()方法可以使一个游离对象转变为持久化对象,并且计划执行一条 update 语句。
2. 若希望Session仅在对象的属性发生变化时, 才执行 update() 语句,可以把映射文件中 <class> 元素的 select-before-update 设为 true,该属性的默认值为 false。(若该对象是持久化对象,且其属性并未发生改变,则就算不配置select-before-update为true,也不会进行update操作)
3. 若更新一个持久化对象,通常不需要显示的调用update方法,因为在调用Transaction的commit()方法时,会先执行session的flush方法。
4. 当update()方法关联一个游离对象时, 如果在 Session 的缓存中已经存在相同OID的持久化对象,会抛出异常,因为在Session 缓存中不能有两个OID相同的对象。
5. 当update()方法关联一个游离对象时,如果在数据库中不存在相应的记录, 也会抛出异常。saveOrUpdate()
首先判断保存的对象是临时对象还是游离对象,若为临时对象,则调用save()方法,若是游离对象,则调用update()方法。
判定对象为临时对象的标准:
标准一: Java 对象的 OID 是否为 null,为null是临时对象,否则是游离对象。
标准二: 如果在映射文件中为 <id> 设置了unsaved-value属性, 则OID取值等于这个unsaved-value属性值的Java对象为临时对象,否则为游离对象。
saveOrUpdate执行流程如下:
delete()
1. Session 的delete()方法既可以删除一个游离对象,也可以删除一个持久化对象。只要 OID 和数据表中一条记录对应,就会准备执行 delete 操作,若 OID 在数据表中没有对应的记录,则抛出异常。
2. Session 的 delete() 方法处理过程为:计划执行一条delete 语句,把对象从 Session 缓存中删除,然后该对象进入删除状态。
3. 默认情况下,在执行delete方法后,对象的id值仍然被保存在对象中,这在某些情形下(例如又对该对象执行saveOrUpdate()方法)会很不方便。Hibernate的配置文件hibernate.cfg.xml中有一个hibernate.use_identifier_rollback属性,其默认值为false,若把它设为true,则在执行delete()方法后,对象的id值将被置为null。