每间隔一段时间,Session
会执行一些必需的SQL语句来把内存中的对象的状态同步到JDBC连接中。这个过程被称为刷出(flush),默认会在下面的时间点执行:
在某些查询执行之前
在调用org.hibernate.Transaction.commit()
的时候
在调用Session.flush()
的时候
涉及的SQL语句会按照下面的顺序发出执行:
所有对实体进行插入的语句,其顺序按照对象执行Session.save()
的时间顺序
所有对实体进行更新的语句
所有进行集合删除的语句
所有对集合元素进行删除,更新或者插入的语句
所有进行集合插入的语句
所有对实体进行删除的语句,其顺序按照对象执行Session.delete()
的时间顺序
(有一个例外是,如果对象使用native
方式来生成ID(持久化标识)的话,它们一执行save就会被插入。)
除非你明确地发出了flush()
指令,关于Session何时会执行这些JDBC调用是完全无法保证的,只能保证它们执行的前后顺序。
当然,Hibernate保证,Query.list(..)
绝对不会返回已经失效的数据,也不会返回错误数据。
也可以改变默认的设置,来让刷出(flush)操作发生的不那么频繁。
FlushMode
类定义了三种不同的方式。
仅在提交时刷出(仅当Hibernate的Transaction
API被使用时有效),
按照刚才说的方式刷出,
以及除非明确使用flush()
否则从不刷出。
最后一种模式对于那些需要长时间保持Session
为打开或者断线状态的长时间运行的工作单元很有用。
(参见 第 11.3.2 节 “扩展周期的session和自动版本化”).
sess = sf.openSession(); Transaction tx = sess.beginTransaction(); sess.setFlushMode(FlushMode.COMMIT); // allow queries to return stale state Cat izi = (Cat) sess.load(Cat.class, id); izi.setName(iznizi); // might return stale data sess.find("from Cat as cat left outer join cat.kittens kitten"); // change to izi is not flushed! ... tx.commit(); // flush occurs sess.close();
刷出(flush)期间,可能会抛出异常。(例如一个DML操作违反了约束) 异常处理涉及到对Hibernate事务性行为的理解,因此我们将在第 11 章 事务和并发中讨论。