📄 transactions.html
字号:
由Hibernate来管理。 </p><p> 对<tt class="literal">after_statement</tt>连接释放方式有一个警告。因为JTA规范的一个很愚蠢的限制,Hibernate不可能自动清理任何未关闭的<tt class="literal">ScrollableResults</tt> 或者<tt class="literal">Iterator</tt>,它们是由<tt class="literal">scroll()</tt>或<tt class="literal">iterate()</tt>产生的。你<span class="emphasis"><em>must</em></span>通过在<tt class="literal">finally</tt>块中,显式调用<tt class="literal">ScrollableResults.close()</tt>或者<tt class="literal">Hibernate.close(Iterator)</tt>方法来释放底层数据库游标。(当然,大部分程序完全可以很容易的避免在CMT代码中出现<tt class="literal">scroll()</tt>或<tt class="literal">iterate()</tt>。) </p></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="transactions-demarcation-exceptions"></a>12.2.3. 异常处理</h3></div></div><div></div></div><p> 如果 <tt class="literal">Session</tt> 抛出异常 (包括任何<tt class="literal">SQLException</tt>), 你应该立即回滚数据库事务,调用 <tt class="literal">Session.close()</tt> ,丢弃该 <tt class="literal">Session</tt>实例。<tt class="literal">Session</tt>的某些方法可能会导致session 处于不一致的状态。所有由Hibernate抛出的异常都视为不可以恢复的。确保在 <tt class="literal">finally</tt> 代码块中调用<tt class="literal">close()</tt>方法,以关闭掉 <tt class="literal">Session</tt>。 </p><p> <tt class="literal">HibernateException</tt>是一个非检查期异常(这不同于Hibernate老的版本), 它封装了Hibernate持久层可能出现的大多数错误。我们的观点是,不应该强迫应用程序开发人员 在底层捕获无法恢复的异常。在大多数软件系统中,非检查期异常和致命异常都是在相应方法调用 的堆栈的顶层被处理的(也就是说,在软件上面的逻辑层),并且提供一个错误信息给应用软件的用户 (或者采取其他某些相应的操作)。请注意,Hibernate也有可能抛出其他并不属于 <tt class="literal">HibernateException</tt>的非检查期异常。这些异常同样也是无法恢复的,应该 采取某些相应的操作去处理。 </p><p> 在和数据库进行交互时,Hibernate把捕获的<tt class="literal">SQLException</tt>封装为Hibernate的 <tt class="literal">JDBCException</tt>。事实上,Hibernate尝试把异常转换为更有实际含义 的<tt class="literal">JDBCException</tt>异常的子类。底层的<tt class="literal">SQLException</tt>可以 通过<tt class="literal">JDBCException.getCause()</tt>来得到。Hibernate通过使用关联到 <tt class="literal">SessionFactory</tt>上的<tt class="literal">SQLExceptionConverter</tt>来 把<tt class="literal">SQLException</tt>转换为一个对应的<tt class="literal">JDBCException</tt> 异常的子类。默认情况下,<tt class="literal">SQLExceptionConverter</tt>可以通过配置dialect 选项指定;此外,也可以使用用户自定义的实现类(参考javadocs <tt class="literal">SQLExceptionConverterFactory</tt>类来了解详情)。标准的 <tt class="literal">JDBCException</tt>子类型是: </p><div class="itemizedlist"><ul type="disc" compact><li><p> <tt class="literal">JDBCConnectionException</tt> - 指明底层的JDBC通讯出现错误 </p></li><li><p> <tt class="literal">SQLGrammarException</tt> - 指明发送的SQL语句的语法或者格式错误 </p></li><li><p> <tt class="literal">ConstraintViolationException</tt> - 指明某种类型的约束违例错误 </p></li><li><p> <tt class="literal">LockAcquisitionException</tt> - 指明了在执行请求操作时,获取 所需的锁级别时出现的错误。 </p></li><li><p> <tt class="literal">GenericJDBCException</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-optimistic"></a>12.3. 乐观并发控制(Optimistic concurrency control)</h2></div></div><div></div></div><p> 唯一能够同时保持高并发和高可伸缩性的方法就是使用带版本化的乐观并发控制。版本检查使用版本号、 或者时间戳来检测更新冲突(并且防止更新丢失)。Hibernate为使用乐观并发控制的代码提供了三种可 能的方法,应用程序在编写这些代码时,可以采用它们。我们已经在前面应用程序长事务那部分展示了 乐观并发控制的应用场景,此外,在单个数据库事务范围内,版本检查也提供了防止更新丢失的好处。 </p><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="transactions-optimistic-manual"></a>12.3.1. 应用程序级别的版本检查(Application version checking)</h3></div></div><div></div></div><p> 未能充分利用Hibernate功能的实现代码中,每次和数据库交互都需要一个新的 <tt class="literal">Session</tt>,而且开发人员必须在显示数据之前从数据库中重 新载入所有的持久化对象实例。这种方式迫使应用程序自己实现版本检查来确保 应用程序事务的隔离,从数据访问的角度来说是最低效的。这种使用方式和 entity EJB最相似。 </p><pre class="programlisting">// foo is an instance loaded by a previous Sessionsession = factory.openSession();Transaction t = session.beginTransaction();int oldVersion = foo.getVersion();session.load( foo, foo.getKey() ); // load the current stateif ( oldVersion!=foo.getVersion ) throw new StaleObjectStateException();foo.setProperty("bar");t.commit();session.close();</pre><p> <tt class="literal">version</tt> 属性使用 <tt class="literal"><version></tt>来映射,如果对象 是脏数据,在同步的时候,Hibernate会自动增加版本号。 </p><p> 当然,如果你的应用是在一个低数据并发环境下,并不需要版本检查的话,你照样可以使用 这种方式,只不过跳过版本检查就是了。在这种情况下,<span class="emphasis"><em>最晚提交生效</em></span> (<span class="emphasis"><em>last commit wins</em></span>)就是你的应用程序长事务的默认处理策略。 请记住这种策略可能会让应用软件的用户感到困惑,因为他们有可能会碰上更新丢失掉却没 有出错信息,或者需要合并更改冲突的情况。 </p><p> 很明显,手工进行版本检查只适合于某些软件规模非常小的应用场景,对于大多数软
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -