📄 transactions.html
字号:
</p><div class="itemizedlist"><ul type="disc"><li><p> <tt class="literal">Session</tt> 是一个非线程安全的类。如果一个<tt class="literal">Session</tt> 实例允许共享的话,那些支持并发运行的东东,例如HTTP request,session beans,或者是 Swing workers,将会导致出现资源争用(race condition)。如果在<tt class="literal">HttpSession</tt>中有 Hibernate 的<tt class="literal">Session</tt>的话(稍后讨论),你应该考虑同步访问你的Http session。 否则,只要用户足够快的点击浏览器的“刷新”,就会导致两个并发运行线程使用同一个 <tt class="literal">Session</tt>。 </p></li><li><p> 一个由Hibernate抛出的异常意味着你必须立即回滚数据库事务,并立即关闭<tt class="literal">Session</tt> (稍后会展开讨论)。如果你的<tt class="literal">Session</tt>绑定到一个应用程序上,你必 须停止该应用程序。回滚数据库事务并不会把你的业务对象退回到事务启动时候的状态。这 意味着数据库状态和业务对象状态不同步。通常情况下,这不是什么问题,因为异常是不可 恢复的,你必须在回滚之后重新开始执行。 </p></li><li><p> <tt class="literal">Session</tt> 缓存了处于持久化状态的每个对象(Hibernate会监视和检查脏数据)。 这意味着,如果你让<tt class="literal">Session</tt>打开很长一段时间,或是仅仅载入了过多的数据, <tt class="literal">Session</tt>占用的内存会一直增长,直到抛出OutOfMemoryException异常。这个 问题的一个解决方法是调用<tt class="literal">clear()</tt> 和<tt class="literal">evict()</tt>来管理 <tt class="literal">Session</tt>的缓存,但是如果你需要大批量数据操作的话,最好考虑 使用存储过程。在<a href="batch.html" title="第 14 章 批量处理(Batch processing)">第 14 章 <i>批量处理(Batch processing)</i></a>中有一些解决方案。在用户会话期间一直保持 <tt class="literal">Session</tt>打开也意味着出现脏数据的可能性很高。 </p></li></ul></div></div></div><div class="sect1" lang="zh-cn"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="transactions-demarcation"></a>12.2. 数据库事务声明</h2></div></div><div></div></div><p> 数据库(或者系统)事务的声明总是必须的。在数据库事务之外,就无法和数据库通讯(这可能会让那些习惯于 自动提交事务模式的开发人员感到迷惑)。永远使用清晰的事务声明,即使只读操作也是如此。进行 显式的事务声明并不总是需要的,这取决于你的事务隔离级别和数据库的能力,但不管怎么说,声明事务总归有益无害。 </p><p> 一个Hibernate应用程序可以运行在非托管环境中(也就是独立运行的应用程序,简单Web应用程序, 或者Swing图形桌面应用程序),也可以运行在托管的J2EE环境中。在一个非托管环境中,Hibernate 通常自己负责管理数据库连接池。应用程序开发人员必须手工设置事务声明,换句话说,就是手工启 动,提交,或者回滚数据库事务。一个托管的环境通常提供了容器管理事务,例如事务装配通过可声 明的方式定义在EJB session beans的部署描述符中。可编程式事务声明不再需要,即使是 <tt class="literal">Session</tt> 的同步也可以自动完成。 </p><p> 让持久层具备可移植性是人们的理想。Hibernate提供了一套称为<tt class="literal">Transaction</tt>的封装API, 用来把你的部署环境中的本地事务管理系统转换到Hibernate事务上。这个API是可选的,但是我们强烈 推荐你使用,除非你用CMT session bean。 </p><p> 通常情况下,结束 <tt class="literal">Session</tt> 包含了四个不同的阶段: </p><div class="itemizedlist"><ul type="disc" compact><li><p> 同步session(flush,刷出到磁盘) </p></li><li><p> 提交事务 </p></li><li><p> 关闭session </p></li><li><p> 处理异常 </p></li></ul></div><p> session的同步(flush,刷出)前面已经讨论过了,我们现在进一步考察在托管和非托管环境下的事务声明和异常处理。 </p><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="transactions-demarcation-nonmanaged"></a>12.2.1. 非托管环境</h3></div></div><div></div></div><p> 如果Hibernat持久层运行在一个非托管环境中,数据库连接通常由Hibernate的连接池机制 来处理。session/transaction处理方式如下所示: </p><pre class="programlisting">//Non-managed environment idiomSession sess = factory.openSession();Transaction tx = null;try { tx = sess.beginTransaction(); // do some work ... tx.commit();}catch (RuntimeException e) { if (tx != null) tx.rollback(); throw e; // or display error message}finally { sess.close();}</pre><p> 你不需要显式<tt class="literal">flush()</tt> <tt class="literal">Session</tt> - 对<tt class="literal">commit()</tt>的调用会自动触发session的同步。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -