在使用nh的过程中,我们一般会在session上开始一个事务,通过session将对象存入数据库,再将这个对象从session上拆离,提交事务,这是一个很正常的流程。
但是有时候这个操作会失效,因为我们并不是直接在数据库上进行操作,其中隔着一个为我们提供持久化服务的NH。
NH的持久化机制
简单的说,NH在数据库层之上实现了一个缓存区,当应用save或者update一个对象时,NH并未将这个对象实际的写入数据库中,而仅仅是在缓存中根据应用的行为做了登记,在真正需要将缓存中的数据flush入数据库时才执行先前登记的行为。
在实际执行的过程中,每个Session是通过几个映射和集合来维护所有与该Session建立了关联的对象以及应用对这些对象所进行的操作的,其中有entityEntries(与Session相关联的对象的映射)、insertions(所有的插入操作集合)、deletions(删除操作集合)、updates(更新操作集合)。下面我就开始解释在最开始的例子中,Hibernate到底是怎样运作的。
- 生成一个事务的对象,并标记当前的 session处于事务状态
- 使用s.save保存对象,这个时候 Session将这个对象放入entityEntries,用来标记该对象已经和当前的会话建立了关联,由于应用对该对象做了保存的操作,Session还要在insertions中登记应用的这个插入行为(行为包括:对象引用、对象id、Session、持久化处理类)。
- 事务提交,需要将所有缓存flush入数据库,Session启动一个事务,并按照insert,update,delete的顺序提交所有之前登记的操作(注意:所有insert执行完毕后才会执行update,这里的特殊处理也可能会将你的程序搞得一团糟,如需要控制操作的执行顺序,要善于使用flush)。
- 在执行insert的行为时只需要访问insertions就足够了。在插入后通知 Session该对象已经插入完毕,这个步骤中需要将entityEntries中对象的existsInDatabase标志置为 true,如果该对象并不存在于entityEntries中,此时Hibernate就认为insertions和entityEntries可能因为线程安全的问题产生了不同步,于是一个net.sf.hibernate.AssertionFailure就被抛出,程序终止。
因为NH的这种缓存机制,在很多书中,作者会提到建议使用事务。这样可以避免写了session.save()或其他后,写入缓存,却没有在数据库中执行的情况。
另一种不使用事务的方式是,在执行完一个操作后flush一下。
参考自:http://wenku.baidu.com/view/c91a3f5c804d2b160b4ec033.html