操纵持久化对象

1 理解session的缓存

如果希望一个Java对象一直处于生命周期中,就必须保证至少有一个变量引用它。customer对象被加入到session的缓存中,以后即使应用程序中的引用变量不再引用customer对象,只要session的缓存还没有被清空,customer对象仍然处于生命周期中。

session的缓存能减少访问数据库的频率,保证缓存中的对象与数据库中的相关记录保持同步。

flush()方法进行清理缓存的操作,执行一系列的SQL语句,但不会提交事务,commit()方法会先调用flush()方法,然后提交事务。

session的setFlushMode()方法用于设定清理缓存的时间点。

2 在hibernate应用中Java对象的状态

当应用程序通过new语句创建了一个对象,这个对象的生命周期就开始了,当不再有任何引用变量引用它,这个对象就结束生命周期,它占用的内存就可以被JVM的垃圾回收器回收。对于需要被持久化的Java对象,在它的生命周期中,可处于以下三个状态之一:

(1) 临时状态(transient):刚刚用new语句创建,还没有被持久化,不处于Session的缓存中。处于临时状态的Java对象被称为临时对象。
(2) 持久化状态(persistent):已经被持久化,加入到Session的缓存中。处于持久化状态的Java对象被称为持久化对象。
(3) 游离状态(detached):已经被持久化,但不再处于Session的缓存中。处于游离状态的Java对象被称为游离对象。

  图Java对象的完整状态转换图

请输入大于10个字符的资源描述图1为Java对象的完整状态转换图,Session的特定方法触发Java对象由一个状态转换到另一个状态。从图1看出,当Java对象处于临时 状态或游离状态,只要不被任何变量引用,就会结束生命周期,它占用的内存就可以被JVM的垃圾回收器回收;当处于持久化状态,由于Session的缓存会 引用它,因此它始终处于生命周期中。


临时对象的特征

临时对象具有以下特征:
(1) 不处于Session的缓存中,也可以说,不被任何一个Session实例关联。
(2) 在数据库中没有对应的记录。

在以下情况下,Java对象进入临时状态:
(1) 当通过new语句刚创建了一个Java对象,它处于临时状态,此时不和数据库中的任何记录对应。
(2) Session的delete()方法能使一个持久化对象或游离对象转变为临时对象。对于游离对象,delete()方法从数据库中删除与它对应的记录;对于持久化对象,delete()方法从数据库中删除与它对应的记录,并且把它从Session的缓存中删除。

持久化对象的特征

持久化对象具有以下特征:
(1) 位于一个Session实例的缓存中,也可以说,持久化对象总是被一个Session实例关联。
(2) 持久化对象和数据库中的相关记录对应。
(3) Session在清理缓存时,会根据持久化对象的属性变化,来同步更新数据库。

Session的许多方法都能够触发Java对象进入持久化状态:
(1) Session的save()方法把临时对象转变为持久化对象。
(2) Session的load()或get()方法返回的对象总是处于持久化状态。
(3) Session的find()方法返回的List集合中存放的都是持久化对象。
(4) Session的update()、saveOrUpdate()和lock()方法使游离对象转变为持久化对象。
(5)当一个持久化对象关联一个临时对象,在允许级联保存的情况下,Session在清理缓存时会把这个临时对象也转变为持久化对象。

Hibernate 保证在同一个Session实例的缓存中,数据库表中的每条记录只对应惟一的持久化对象。例如对于以下代码,共创建了两个Session实例: session1和session2。session1和session2拥有各自的缓存。在session1的缓存中,只会有惟一的OID为1的 Customer持久化对象,在session2的缓存中,也只会有惟一的OID为1的Customer持久化对象。因此在内存中共有两个 Customer持久化对象,一个属于session1的缓存,一个属于session2的缓存。引用变量a和b都引用session1缓存中的 Customer持久化对象,而引用变量c引用session2缓存中的Customer持久化对象:

Session session1=sessionFactory.openSession();
Session session2=sessionFactory.openSession();
Transaction tx1 = session1.beginTransaction();
Transaction tx2 = session2.beginTransaction();

Customer a=(Customer)session1.load(Customer.class,new Long(1));
Customer b=(Customer)session1.load(Customer.class,new Long(1));
Customer c=(Customer)session2.load(Customer.class,new Long(1));

System.out.println(a= =b); //true
System.out.println(a= =c); //false

tx1.commit();
tx2.commit();
session1.close();
session2.close();

Java对象的持久化状态是相对于某个具体的Session实例的,以下代码试图使一个Java对象同时被两个Session实例关联:

Session session1=sessionFactory.openSession();
Session session2=sessionFactory.openSession();
Transaction tx1 = session1.beginTransaction();
Transaction tx2 = session2.beginTransaction();

Customer c=(Customer)session1.load(Customer.class,new Long(1)); //Customer对象被session1关联
session2.update(c); //Customer对象被session2关联
c.setName("Jack"); //修改Customer对象的属性

tx1.commit(); //执行update语句
tx2.commit(); //执行update语句
session1.close();
session2.close();

当执行session1的load()方法时,OID为1的Customer对象被加入到session1的缓存中,因此它是session1的持 久化对象,此时它还没有被session2关联,因此相对于session2,它处于游离状态。当执行session2的update()方法时, Customer对象被加入到session2的缓存中,因此也成为session2的持久化对象。接下来修改Customer对象的name属性,会导 致两个Session实例在清理各自的缓存时,都执行相同的update语句:

update CUSTOMERS set NAME='Jack' …… where ID=1;
在实际应用程序中,应该避免一个Java对象同时被多个Session实例关联,因为这会导致重复执行SQL语句,并且极容易出现一些并发问题。

游离对象的特征

游离对象具有以下特征:
(1) 不再位于Session的缓存中,也可以说,游离对象不被Session关联。
(2) 游离对象是由持久化对象转变过来的,因此在数据库中可能还存在与它对应的记录(前提条件是没有其他程序删除了这条记录)。

游离对象与临时对象的相同之处在于,两者都不被Session关联,因此Hibernate不会保证它们的属性变化与数据库保持同步。游离对象与临时对象的区别在于:前者是由持久化对象转变过来的,因此可能在数据库中还存在对应的记录,而后者在数据库中没有对应的记录。

Session的以下方法使持久化对象转变为游离对象:
(1) 当调用Session的close()方法时,Session的缓存被清空,缓存中的所有持久化对象都变为游离对象。如果在应用程序中没有引用变量引用这些游离对象,它们就会结束生命周期。
(2) Session的evict()方法能够从缓存中删除一个持久化对象,使它变为游离状态。当Session的缓存中保存了大量的持久化对象,会消耗许多内 存空间,为了提高性能,可以考虑调用evict()方法,从缓存中删除一些持久化对象。但是多数情况下不推荐使用evict()方法,而应该通过查询语 言,或者显式的导航来控制对象图的深度。

3 session的保存,更新,删除和查询方法
无论Java对象处于临时状态,持久化状态还是游离状态,应用程序都不应修改它的OID。

如果希望session仅仅当customer对象的属性时,才执行update语句:
class name="mypack.Customer" table="CUSTOMERS" select-before-update="true"

session的load()和get()方法能根据给定的OID从数据库中加载一个持久化对象,当数据库不存在与OID对于的记录时,load()方法抛出net.sf.hibernate.OjbectNotFoundException异常,而get()方法返回null.

4 与触发器协同工作
假如session的save(),update(),saveOrUpdate(),delete()方法会激发一个触发器,而这个触发器的行为会导致session的缓存与数据库不一致,解决方法是在执行完这个操作之后,立即调用session的flush()和refresh()方法,迫使session的缓存与数据库同步。
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值