📄 objectstate.html
字号:
"SELECT {cat.*} FROM CAT {cat} WHERE ROWNUM<10", "cat", Cat.class).list();</pre><pre class="programlisting">List cats = session.createSQLQuery( "SELECT {cat}.ID AS {cat.id}, {cat}.SEX AS {cat.sex}, " + "{cat}.MATE AS {cat.mate}, {cat}.SUBCLASS AS {cat.class}, ... " + "FROM CAT {cat} WHERE ROWNUM<10", "cat", Cat.class).list()</pre><p> 和Hibernate查询一样,SQL查询也可以包含命名参数和占位参数。 可以在<a href="querysql.html" title="第 17 章 Native SQL查询">第 17 章 <i>Native SQL查询</i></a>找到更多关于Hibernate中原生SQL(native SQL)的信息。 </p></div></div><div class="sect1" lang="zh-cn"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="objectstate-modifying"></a>11.5. 修改持久对象</h2></div></div><div></div></div><p> <span class="emphasis"><em>事务中的持久实例</em></span>(就是通过<tt class="literal">session</tt>装载、保存、创建或者查询出的对象) 被应用程序操作所造成的任何修改都会在<tt class="literal">Session</tt>被<span class="emphasis"><em>刷出(flushed)</em></span>的时候被持久化(本章后面会详细讨论)。 这里不需要调用某个特定的方法(比如<tt class="literal">update()</tt>,设计它的目的是不同的)将你的修改持久化。 所以最直接的更新一个对象的方法就是在<tt class="literal">Session</tt>处于打开状态时<tt class="literal">load()</tt>它,然后直接修改即可: </p><pre class="programlisting">DomesticCat cat = (DomesticCat) sess.load( Cat.class, new Long(69) );cat.setName("PK");sess.flush(); // changes to cat are automatically detected and persisted</pre><p> 有时这种程序模型效率低下,因为它在同一Session里需要一条SQL <tt class="literal">SELECT</tt>语句(用于加载对象) 以及一条SQL <tt class="literal">UPDATE</tt>语句(持久化更新的状态)。 为此Hibernate提供了另一种途径,使用脱管(detached)实例。 </p><p> <span class="emphasis"><em>请注意Hibernate本身不提供直接执行<tt class="literal">UPDATE</tt>或<tt class="literal">DELETE</tt>语句的API。 Hibernate提供的是<span class="emphasis"><em>状态管理(state management)</em></span>服务,你不必考虑要使用的<span class="emphasis"><em>语句(statements)</em></span>。 JDBC是出色的执行SQL语句的API,任何时候调用<tt class="literal">session.connection()</tt>你都可以得到一个JDBC <tt class="literal">Connection</tt>对象。 此外,在联机事务处理(OLTP)程序中,大量操作(mass operations)与对象/关系映射的观点是相冲突的。 Hibernate的将来版本可能会提供专门的进行大量操作(mass operation)的功能。 参考<a href="batch.html" title="第 14 章 批量处理(Batch processing)">第 14 章 <i>批量处理(Batch processing)</i></a>,寻找一些可用的批量(batch)操作技巧。</em></span> </p></div><div class="sect1" lang="zh-cn"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="objectstate-detached"></a>11.6. 修改脱管(Detached)对象</h2></div></div><div></div></div><p> 很多程序需要在某个事务中获取对象,然后将对象发送到界面层去操作,最后在一个新的事务保存所做的修改。 在高并发访问的环境中使用这种方式,通常使用附带版本信息的数据来保证这些“长“工作单元之间的隔离。 </p><p> Hibernate通过提供使用<tt class="literal">Session.update()</tt>或<tt class="literal">Session.merge()</tt>方法 重新关联脱管实例的办法来支持这种模型。 </p><pre class="programlisting">// in the first sessionCat cat = (Cat) firstSession.load(Cat.class, catId);Cat potentialMate = new Cat();firstSession.save(potentialMate);// in a higher layer of the applicationcat.setMate(potentialMate);// later, in a new sessionsecondSession.update(cat); // update catsecondSession.update(mate); // update mate</pre><p> 如果具有<tt class="literal">catId</tt>持久化标识的<tt class="literal">Cat</tt>之前已经被<tt class="literal">另一Session(secondSession)</tt>装载了, 应用程序进行重关联操作(reattach)的时候会抛出一个异常。 </p><p> 如果你确定当前session没有包含与之具有相同持久化标识的持久实例,使用<tt class="literal">update()</tt>。 如果想随时合并你的的改动而不考虑session的状态,使用<tt class="literal">merge()</tt>。 换句话说,在一个新session中通常第一个调用的是<tt class="literal">update()</tt>方法,以便保证重新关联脱管(detached)对象的操作首先被执行。 </p><p> 希望相关联的脱管对象(通过引用“可到达”的脱管对象)的数据也要更新到数据库时(并且也<span class="emphasis"><em>仅仅</em></span>在这种情况), 应用程序需要对该相关联的脱管对象单独调用<tt class="literal">update()</tt> 当然这些可以自动完成,即通过使用<span class="emphasis"><em>传播性持久化(transitive persistence)</em></span>,请看<a href="objectstate.html#objectstate-transitive" title="11.11. 传播性持久化(transitive persistence)">第 11.11 节 “传播性持久化(transitive persistence)”</a>。 </p><p> <tt class="literal">lock()</tt>方法也允许程序重新关联某个对象到一个新session上。不过,该脱管(detached)的对象必须是没有修改过的! </p><pre class="programlisting">//just reassociate:sess.lock(fritz, LockMode.NONE);//do a version check, then reassociate:sess.lock(izi, LockMode.READ);//do a version check, using SELECT ... FOR UPDATE, then reassociate:sess.lock(pk, LockMode.UPGRADE);</pre><p> 请注意,<tt class="literal">lock()</tt>可以搭配多种<tt class="literal">LockMode</tt>, 更多信息请阅读API文档以及关于事务处理(transaction handling)的章节。重新关联不是<tt class="literal">lock()</tt>的唯一用途。 </p><p> 其他用于长时间工作单元的模型会在<a href="transactions.html#transactions-optimistic" title="12.3. 乐观并发控制(Optimistic concurrency control)">第 12.3 节 “乐观并发控制(Optimistic concurrency control)”</a>中讨论。 </p></div><div class="sect1" lang="zh-cn"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="objectstate-saveorupdate"></a>11.7. 自动状态检测</h2></div></div><div></div></div><p> Hibernate的用户曾要求一个既可自动分配新持久化标识(identifier)保存瞬时(transient)对象,又可更新/重新关联脱管(detached)实例的通用方法。 <tt class="literal">saveOrUpdate()</tt>方法实现了这个功能。 </p><pre class="programlisting">// in the first sessionCat cat = (Cat) firstSession.load(Cat.class, catID);// in a higher tier of the applicationCat mate = new Cat();cat.setMate(mate);// later, in a new sessionsecondSession.saveOrUpdate(cat); // update existing state (cat has a non-null id)secondSession.saveOrUpdate(mate); // save the new instance (mate has a null id)</pre><p> <tt class="literal">saveOrUpdate()</tt>用途和语义可能会使新用户感到迷惑。 首先,只要你没有尝试在某个session中使用来自另一session的实例,你应该就不需要使用<tt class="literal">update()</tt>, <tt class="literal">saveOrUpdate()</tt>,或<tt class="literal">merge()</tt>。有些程序从来不用这些方法。 </p><p> 通常下面的场景会使用<tt class="literal">update()</tt>或<tt class="literal">saveOrUpdate()</tt>: </p><div class="itemizedlist"><ul type="disc" compact><li><p> 程序在第一个session中加载对象 </p></li><li><p> 该对象被传递到表现层 </p></li><li><p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -