Hibernate扩展周期的Session和自动版本化
今天我们主要介绍扩展周期的Hibernate session和自动版本化,望读者能够加以借鉴。
单个Hibernate Session实例和它所关联的所有持久化对象实例都被用于整个对话,这被称为session-per-conversation。Hibernate在同步的时候进行对象实例的版本检查,如果检测到并发修 改则抛出异常。由开发人员来决定是否需要捕获和处理这个异常(通常的抉择是给用户 提供一个合并更改,或者在无脏数据情况下重新进行业务对话的机会)。
在等待用户交互的时候,Hibernate Session 断开底层的JDBC连接。这种方式 以数据库访问的角度来说是最高效的方式。应用程序不需要关心版本检查或脱管对象实例 的重新关联,在每个数据库事务中,应用程序也不需要载入读取对象实例。
// foo is an instance loaded earlier by the old session Transaction t = session.beginTransaction(); // Obtain a new JDBC connection, start transaction foo.setProperty("bar"); session.flush(); // Only for last transaction in conversation t.commit(); // Also return JDBC connection session.close(); // Only for last transaction in conversation
foo对象知道它是在哪个Session中被装入的。在一个旧session中开启一个新的数据库事务,会导致session获取一个新的连接,并恢复session的功能。
将数据库事务提交,使得session从JDBC连接断开,并将此连接交还给连接池。在重新连接之后,要强制对你没有更新的数据进行一次版本检查,你可以对所有可能被其他事务修改过的对象,使用参数LockMode.READ来调用Session.lock()。你不用lock任何你正在更新的数据。
一般你会在扩展的Session上设置FlushMode.NEVER,因此只有最后一个数据库事务循环才会真正的吧整个对话中发生的修改发送到数据库。因此,只有这最后一次数据库事务才会包含flush()操作,然后在整个对话结束后,还要close()这个session。
如果在用户思考的过程中,Session因为太大了而不能保存,那么这种模式是有 问题的。举例来说,一个HttpSession应该尽可能的小。
由于 Session是一级缓存,并且保持了所有被载入过的对象,因此 我们只应该在那些少量的request/response情况下使用这种策略。你应该只把一个Session用于单个对话,因为它很快就会出现脏数据。
注意:
早期的Hibernate版本需要明确的对Session进行disconnec和reconnect。这些方法现在已经过时了,打开事务和关闭事务会起到同样的效果。