﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-微蓝领域-文章分类-Hibernate</title><link>http://www.blogjava.net/hilor/category/25040.html</link><description>我的学习档案馆</description><language>zh-cn</language><lastBuildDate>Sun, 30 Mar 2008 16:36:00 GMT</lastBuildDate><pubDate>Sun, 30 Mar 2008 16:36:00 GMT</pubDate><ttl>60</ttl><item><title>关于OpenSessionInView</title><link>http://www.blogjava.net/hilor/articles/189348.html</link><dc:creator>hilor</dc:creator><author>hilor</author><pubDate>Fri, 28 Mar 2008 12:38:00 GMT</pubDate><guid>http://www.blogjava.net/hilor/articles/189348.html</guid><wfw:comment>http://www.blogjava.net/hilor/comments/189348.html</wfw:comment><comments>http://www.blogjava.net/hilor/articles/189348.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hilor/comments/commentRss/189348.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hilor/services/trackbacks/189348.html</trackback:ping><description><![CDATA[附http://www.javaeye.com/topic/14631<br />
OpenSessionInViewFilter讨论<br />
Hibernate的Lazy初始化1:n关系时，你必须保证是在同一个Session内部使用这个关系集合，不然Hiernate将抛出例外。
<p class="paragraph">另外，你不愿意你的DAO测试代码每次都打开关系Session，因此，我们一般会采用OpenSessionInView模式。
</p>
<h3 class="heading-1"><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="0"></a><strong style="color: black; background-color: #ffff66;">OpenSessionInViewFilter</strong>解决Web应用程序的问题
</h3>
如果程序是在正常的Web程序中运行，那么Spring的<strong style="color: black; background-color: #ffff66;">OpenSessionInViewFilter</strong>能够解决问题，它：
<div class="code">
<pre><span class="java-keyword">protected</span> void doFilterInternal(HttpServletRequest request, <br />
HttpServletResponse response,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;     FilterChain filterChain) <span class="java-keyword">throws</span> ServletException, IOException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SessionFactory sessionFactory = lookupSessionFactory();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.debug(<span class="java-quote">"Opening Hibernate Session in <strong style="color: black; background-color: #ffff66;">OpenSessionInViewFilter</strong>"</span>);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Session session = getSession(sessionFactory);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TransactionSynchronizationManager.bindResource(sessionFactory, <br />
<span class="java-keyword">new</span> SessionHolder(session));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">try</span> {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;filterChain.doFilter(request, response);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">finally</span> {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TransactionSynchronizationManager.unbindResource(sessionFactory);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.debug(<span class="java-quote">"Closing Hibernate Session in <strong style="color: black; background-color: #ffff66;">OpenSessionInViewFilter</strong>"</span>);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;closeSession(session, sessionFactory);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</pre>
</div>
可以看到，这个Filter在request开始之前，把sessionFactory绑定到TransactionSynchronizationManager，和这个SessionHolder相关。这个意味着所有request执行过程中将使用这个session。而在请求结束后，将和这个sessionFactory对应的session解绑，并且关闭Session。
<p class="paragraph">为什么绑定以后，就可以防止每次不会新开一个Session呢？看看HibernateDaoSupport的情况： </p>
<div class="code">
<pre><span class="java-keyword">public</span> <span class="java-keyword">final</span> void setSessionFactory(SessionFactory sessionFactory) {<br />
<span class="java-keyword">this</span>.hibernateTemplate = <span class="java-keyword">new</span> HibernateTemplate(sessionFactory);<br />
}<br />
<span class="java-keyword">protected</span> <span class="java-keyword">final</span> HibernateTemplate getHibernateTemplate() {<br />
<span class="java-keyword">return</span> hibernateTemplate;<br />
}</pre>
</div>
<p class="paragraph">我们的DAO将使用这个template进行操作： </p>
<div class="code">
<pre><span class="java-keyword">public</span> <span class="java-keyword">abstract</span> class BaseHibernateObjectDao<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">extends</span> HibernateDaoSupport<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">implements</span> BaseObjectDao {<br />
<p class="paragraph"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">protected</span> BaseEntityObject getByClassId(<span class="java-keyword">final</span> <span class="java-object">long</span> id) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BaseEntityObject obj =<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(BaseEntityObject) getHibernateTemplate()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.execute(<span class="java-keyword">new</span> HibernateCallback() {<br />
</p>
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">public</span> <span class="java-object">Object</span> doInHibernate(Session session)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">throws</span> HibernateException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">return</span> session.get(getPersistentClass(), <br />
<span class="java-keyword">new</span> <span class="java-object">Long</span>(id));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</p>
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">return</span> obj;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</p>
<br />
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">public</span> void save(BaseEntityObject entity) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getHibernateTemplate().saveOrUpdate(entity);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</p>
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">public</span> void remove(BaseEntityObject entity) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">try</span> {<br />
</p>
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getHibernateTemplate().delete(entity);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <span class="java-keyword">catch</span> (Exception e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">throw</span> <span class="java-keyword">new</span> FlexEnterpriseDataAccessException(e);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</p>
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">public</span> void refresh(<span class="java-keyword">final</span> BaseEntityObject entity) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getHibernateTemplate().execute(<span class="java-keyword">new</span> HibernateCallback() {<br />
</p>
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">public</span> <span class="java-object">Object</span> doInHibernate(Session session)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">throws</span> HibernateException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.refresh(entity);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">return</span> <span class="java-keyword">null</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</p>
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">public</span> void replicate(<span class="java-keyword">final</span> <span class="java-object">Object</span> entity) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getHibernateTemplate().execute(<span class="java-keyword">new</span> HibernateCallback() {<br />
</p>
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">public</span> <span class="java-object">Object</span> doInHibernate(Session session)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">throws</span> HibernateException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.replicate(entity, <br />
ReplicationMode.OVERWRITE);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">return</span> <span class="java-keyword">null</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</p>
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</p>
</pre>
</div>
而HibernateTemplate试图每次在execute之前去获得Session，执行完就力争关闭Session
<div class="code">
<pre><span class="java-keyword">public</span> <span class="java-object">Object</span> execute(HibernateCallback action) <span class="java-keyword">throws</span> DataAccessException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Session session = (!<span class="java-keyword">this</span>.allowCreate ?<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SessionFactoryUtils.getSession(getSessionFactory(), <br />
<span class="java-keyword">false</span>) :<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SessionFactoryUtils.getSession(getSessionFactory(),<br />
getEntityInterceptor(),<br />
getJdbcExceptionTranslator()));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-object">boolean</span> existingTransaction =  <br />
TransactionSynchronizationManager.hasResource(getSessionFactory());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">if</span> (!existingTransaction &amp;&amp; getFlushMode() == FLUSH_NEVER) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.setFlushMode(FlushMode.NEVER);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">try</span> {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-object">Object</span> result = action.doInHibernate(session);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flushIfNecessary(session, existingTransaction);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">return</span> result;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">catch</span> (HibernateException ex) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">throw</span> convertHibernateAccessException(ex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">catch</span> (SQLException ex) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">throw</span> convertJdbcAccessException(ex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">catch</span> (RuntimeException ex) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// callback code threw application exception<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">throw</span> ex;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">finally</span> {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SessionFactoryUtils.closeSessionIfNecessary(<br />
session, getSessionFactory());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</pre>
</div>
而这个SessionFactoryUtils能否得到当前的session以及closeSessionIfNecessary是否真正关闭session，端取决于这个session是否用sessionHolder和这个sessionFactory在我们最开始提到的TransactionSynchronizationManager绑定。
<div class="code">
<pre><span class="java-keyword">public</span> <span class="java-keyword">static</span> void closeSessionIfNecessary(Session session, <br />
SessionFactory sessionFactory)   <br />
<span class="java-keyword">throws</span> CleanupFailureDataAccessException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">if</span> (session == <span class="java-keyword">null</span> || <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   TransactionSynchronizationManager.hasResource(sessionFactory)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">return</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.debug(<span class="java-quote">"Closing Hibernate session"</span>);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">try</span> {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">catch</span> (JDBCException ex) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// SQLException underneath<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">throw</span> <span class="java-keyword">new</span> CleanupFailureDataAccessException(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-quote">"Cannot close Hibernate session"</span>, ex.getSQLException());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">catch</span> (HibernateException ex) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-keyword">throw</span> <span class="java-keyword">new</span> CleanupFailureDataAccessException(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="java-quote">"Cannot close Hibernate session"</span>, ex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</pre>
</div>
<h3 class="heading-1">HibernateInterceptor和OpenSessionInViewInterceptor的问题 </h3>
<p class="paragraph">使用同样的方法，这两个Interceptor可以用来解决问题。但是关键的不同之处在于，它们的力度只能定义在DAO或业务方法上，而不是在我们的Test方法上，除非我们把它们应用到TestCase的方法上，但你不大可能为TestCase去定义一个接口，然后把Interceptor应用到这个接口的某些方法上。直接使用HibernateTransactionManager也是一样的。因此，如果我们有这样的测试：
</p>
<div class="code">
<pre>Category parentCategory  = <span class="java-keyword">new</span> Category ();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parentCategory.setName(<span class="java-quote">"parent"</span>);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dao.save(parentCategory);<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Category childCategory  = <span class="java-keyword">new</span> Category();<br />
childCategory.setName(<span class="java-quote">"child"</span>);<br />
</p>
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parentCategory.addChild(childCategory);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dao.save(childCategory);</p>
<br />
<p class="paragraph">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Category savedParent = dao.getCategory(<span class="java-quote">"parent"</span>);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Category savedChild = (Category ) savedParent.getChildren().get(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertEquals(savedChild, childCategory);<br />
</p>
</pre>
</div>
将意味着两件事情：
<ul class="minus">
    <li>每次DAO执行都会启动一个session和关闭一个session
    </li>
    <li>如果我们定义了一个lazy的关系，那么最后的Category savedChild = (Category )
    savedParent.getChildren().get(0);将会让hibernate报错。 </li>
</ul>
<h3 class="heading-1">解决方案 </h3>
<p class="paragraph">一种方法是对TestCase应用Interceptor或者TransactionManager，但这个恐怕会造成很多麻烦。除非是使用增强方式的AOP.我前期采用这种方法(Aspectwerkz)，在Eclipse里面也跑得含好。
</p>
<p class="paragraph">另一种方法是在TestCase的setup和teardown里面实现和Filter完全一样的处理，其他的TestCase都从这个TestCase继承，这种方法是我目前所使用的。
</p>
<img src ="http://www.blogjava.net/hilor/aggbug/189348.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hilor/" target="_blank">hilor</a> 2008-03-28 20:38 <a href="http://www.blogjava.net/hilor/articles/189348.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>open session in view 的使用</title><link>http://www.blogjava.net/hilor/articles/189346.html</link><dc:creator>hilor</dc:creator><author>hilor</author><pubDate>Fri, 28 Mar 2008 12:29:00 GMT</pubDate><guid>http://www.blogjava.net/hilor/articles/189346.html</guid><wfw:comment>http://www.blogjava.net/hilor/comments/189346.html</wfw:comment><comments>http://www.blogjava.net/hilor/articles/189346.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hilor/comments/commentRss/189346.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hilor/services/trackbacks/189346.html</trackback:ping><description><![CDATA[<span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">在没有使用</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">Spring</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">提供的</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">Open Session In View</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">情况下，因需要在</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">service(or Dao)</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">层里把</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">session</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">关闭，所以</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">lazy loading </span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">为</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">true</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">的话，要在应用层内把关系集合都初始化，如</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;"> company.getEmployees()</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">，否则</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">Hibernate</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">抛</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">session already closed Exception;</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">&nbsp;&nbsp;&nbsp; Open Session In View</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">提供了一种简便的方法，较好地解决了</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">lazy loading</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">问题</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">.</span>
<p><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;"><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">&nbsp;&nbsp;&nbsp; </span>它有两种配置方式<font face="Verdana">OpenSessionInViewInterceptor</font></span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">和<span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">OpenSessionInViewFilter(具体参看<a title="SpringSide" target="_blank" href="http://www.springside.org.cn/"><strong><font color="#78a515">SpringSide</font></strong></a>)</span></span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">，功能相同，只是一个在</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">web.xml</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">配置，另一个在</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">application.xml</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">配置而已。</span></p>
<p><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">&nbsp;&nbsp;&nbsp; Open Session In View</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">在</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">request</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">把</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">session</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">绑定到当前</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">thread</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">期间一直保持</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">hibernate session</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">在</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">open</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">状态，使</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">session</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">在</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">request</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">的整个期间都可以使用，如在</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">View</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">层里</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">PO</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">也可以</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">lazy loading</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">数据，如</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;"> ${ company.employees }</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">。当</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">View </span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">层逻辑完成后，才会通过</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">Filter</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">的</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">doFilter</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">方法或</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">Interceptor</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">的</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">postHandle</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">方法自动关闭</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">session</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">。</span></p>
<br />
<span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;"><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">
<div class="head">
<pre class="java">
<div class="head">OpenSessionInViewInterceptor配置</div>
<ol>
    <li class="li1">
    <div class="de1">&lt;beans&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">  &lt;bean name=<span class="st0"><font color="#0000ff">"openSessionInViewInterceptor"</font></span> </div>
    </li>
    <li class="li1">
    <div class="de1"><span class="kw2"><strong><font color="#7f0055">class</font></strong></span>=<span class="st0"><font color="#0000ff">"org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor"</font></span>&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;property name=<span class="st0"><font color="#0000ff">"sessionFactory"</font></span>&gt;</div>
    </li>
    <li class="li1">
    <div class="de1">      &lt;ref bean=<span class="st0"><font color="#0000ff">"sessionFactory"</font></span>/&gt;</div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;/property&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">  &lt;/bean&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">  &lt;bean id=<span class="st0"><font color="#0000ff">"urlMapping"</font></span> </div>
    </li>
    <li class="li1">
    <div class="de1"><span class="kw2"><strong><font color="#7f0055">class</font></strong></span>=<span class="st0"><font color="#0000ff">"org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"</font></span>&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;property name=<span class="st0"><font color="#0000ff">"interceptors"</font></span>&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">      &lt;list&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">        &lt;ref bean=<span class="st0"><font color="#0000ff">"openSessionInViewInterceptor"</font></span>/&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">      &lt;/list&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;/property&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;property name=<span class="st0"><font color="#0000ff">"mappings"</font></span>&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">    ... </div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;/property&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">  &lt;/bean&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">... </div>
    </li>
    <li class="li1">
    <div class="de1">&lt;/beans&gt; </div>
    </li>
</ol>
</pre>
</div>
<div class="head">
<pre class="java">
<div class="head">OpenSessionInViewFilter配置</div>
<ol>
    <li class="li1">
    <div class="de1">&lt;web-app&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">... </div>
    </li>
    <li class="li1">
    <div class="de1">  &lt;filter&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;filter-name&gt;hibernateFilter&lt;/filter-name&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;filter-class&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">      org.<span class="me1">springframework</span>.<span class="me1">orm</span>.<span class="me1">hibernate3</span>.<span class="me1">support</span>.<span class="me1">OpenSessionInViewFilter</span> </div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;/filter-class&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;!-- singleSession默认为true,若设为false则等于没用<span class="me1">OpenSessionInView --&gt;</span></div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;init-param&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">      &lt;param-name&gt;singleSession&lt;/param-name&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">      &lt;param-value&gt;true&lt;/param-value&gt;</div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;/init-param&gt;</div>
    </li>
    <li class="li1">
    <div class="de1">  &lt;/filter&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">... </div>
    </li>
    <li class="li1">
    <div class="de1">  &lt;filter-mapping&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;filter-name&gt;hibernateFilter&lt;/filter-name&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">    &lt;url-pattern&gt;*.<span class="me1">do</span>&lt;/url-pattern&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">  &lt;/filter-mapping&gt; </div>
    </li>
    <li class="li1">
    <div class="de1">... </div>
    </li>
    <li class="li1">
    <div class="de1">&lt;/web-app&gt; </div>
    </li>
</ol>
</pre>
<p>很多人在使用OpenSessionInView过程中提及一个错误：</p>
<pre class="java">
<ol>
    <li class="li1">
    <div class="de1">org.<span class="me1">springframework</span>.<span class="me1">dao</span>.<span class="me1">InvalidDataAccessApiUsageException</span>: Write operations </div>
    </li>
    <li class="li1">
    <div class="de1">are not allowed in read-only mode <span class="br0"><font color="#663300">(</font></span>FlushMode.<span class="me1">NEVER</span><span class="br0"><font color="#663300">)</font></span> - turn your Session into </div>
    </li>
    <li class="li1">
    <div class="de1">FlushMode.<span class="me1">AUTO</span> or remove <span class="st0"><font color="#0000ff">'readOnly'</font></span> marker from transaction definition </div>
    </li>
</ol>
</pre>
<p>看看OpenSessionInViewFilter里的几个方法</p>
<pre class="java">
<ol>
    <li class="li1">
    <div class="de1"><span class="kw2"><strong><font color="#7f0055">protected</font></strong></span> <span class="kw4"><font color="#f63333">void</font></span> doFilterInternal<span class="br0"><font color="#663300">(</font></span>HttpServletRequest request, <br />
    HttpServletResponse response,FilterChain filterChain<span class="br0"><font color="#663300">)</font></span> <br />
    <span class="kw2"><strong><font color="#7f0055">throws</font></strong></span> ServletException, <span class="kw3"><font color="#ff0000">IOException</font></span> <span class="br0"><font color="#663300">{<br />
    </font></span>　SessionFactory sessionFactory = lookupSessionFactory<font color="#663300"><span class="br0">(</span><span class="br0">)</span></font>;<br />
    logger.<span class="me1">debug</span><span class="br0"><font color="#663300">(</font></span><span class="st0"><font color="#0000ff">"Opening Hibernate Session in OpenSessionInViewFilter"</font></span><span class="br0"><font color="#663300">)</font></span>;<br />
    Session session = getSession<span class="br0"><font color="#663300">(</font></span>sessionFactory<span class="br0"><font color="#663300">)</font></span>;<br />
    TransactionSynchronizationManager.<span class="me1">bindResource</span><span class="br0"><font color="#663300">(<br />
    </font></span>　　sessionFactory, <span class="kw2"><strong><font color="#7f0055">new</font></strong></span> SessionHolder<span class="br0"><font color="#663300">(</font></span>session<font color="#663300"><span class="br0">)</span><span class="br0">)</span></font>;<br />
    <span class="kw2"><strong><font color="#7f0055">try</font></strong></span> <span class="br0"><font color="#663300">{<br />
    </font></span>　　filterChain.<span class="me1">doFilter</span><span class="br0"><font color="#663300">(</font></span>request, response<span class="br0"><font color="#663300">)</font></span>;<br />
    <span class="br0"><font color="#663300">}<br />
    </font></span><span class="kw2"><strong><font color="#7f0055">　finally</font></strong></span> <span class="br0"><font color="#663300">{<br />
    </font></span>　TransactionSynchronizationManager.<span class="me1">unbindResource</span><span class="br0"><font color="#663300">(</font></span>sessionFactory<span class="br0"><font color="#663300">)</font></span>;<br />
    logger.<span class="me1">debug</span><span class="br0"><font color="#663300">(</font></span><span class="st0"><font color="#0000ff">"Closing Hibernate Session in OpenSessionInViewFilter"</font></span><span class="br0"><font color="#663300">)</font></span>;<br />
    closeSession<span class="br0"><font color="#663300">(</font></span>session, sessionFactory<span class="br0"><font color="#663300">)</font></span>;<br />
    <font color="#663300"><span class="br0">}<br />
    </span><span class="br0">}</span></font><span class="br0"><br />
    <br />
    <br />
    <br />
    <br />
    </span>&nbsp;</div>
    </li>
    <li class="li1">
    <div class="de1"><span class="kw2"><strong><font color="#7f0055">protected</font></strong></span> Session getSession<span class="br0"><font color="#663300">(</font></span>SessionFactory sessionFactory<span class="br0"><font color="#663300">)<br />
    </font></span><span class="kw2"><strong><font color="#7f0055">throws</font></strong></span> DataAccessResourceFailureException <span class="br0"><font color="#663300">{<br />
    </font></span>　Session session = SessionFactoryUtils.<span class="me1">getSession</span><span class="br0"><font color="#663300">(</font></span>sessionFactory, <span class="kw2"><strong><font color="#7f0055">true</font></strong></span><span class="br0"><font color="#663300">)</font></span>;<br />
    session.<span class="me1">setFlushMode</span><span class="br0"><font color="#663300">(</font></span>FlushMode.<span class="me1">NEVER</span><span class="br0"><font color="#663300">)</font></span>;<br />
    <span class="kw2"><strong><font color="#7f0055">return</font></strong></span> session;<br />
    <span class="br0"><font color="#663300">}</font></span></div>
    </li>
    <li class="li1"><span class="kw2"><br />
    <strong><font color="#7f0055">protected</font></strong></span> <span class="kw4"><font color="#f63333">void</font></span> closeSession<span class="br0"><font color="#663300">(</font></span>Session session, SessionFactory sessionFactory<span class="br0"><font color="#663300">)<br />
    </font></span><span class="kw2"><strong><font color="#7f0055">throws</font></strong></span> CleanupFailureDataAccessException <span class="br0"><font color="#663300">{<br />
    </font></span>　SessionFactoryUtils.<span class="me1">closeSessionIfNecessary</span><span class="br0"><font color="#663300">(</font></span>session, sessionFactory<span class="br0"><font color="#663300">)</font></span>;<br />
    <span class="br0"><font color="#663300">}</font></span> </li>
</ol>
</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;
可以看到OpenSessionInViewFilter在getSession的时候,会把获取回来的session的flush mode
设为FlushMode.NEVER。然后把该sessionFactory绑定到
TransactionSynchronizationManager，使request的整个过程都使用同一个session，在请求过后再接除该
sessionFactory的绑定，最后<span class="me1">closeSessionIfNecessary</span>根据该
session是否已和transaction绑定来决定是否关闭session。在这个过程中，若HibernateTemplate
发现自当前session有不是readOnly的transaction，就会获取到FlushMode.AUTO
Session，使方法拥有写权限。</p>
<pre class="java">
<ol>
    <li class="li1">
    <div class="de1"><span class="kw2"><strong><font color="#7f0055">public</font></strong></span> <span class="kw2"><strong><font color="#7f0055">static</font></strong></span> <span class="kw4"><font color="#f63333">void</font></span> closeSessionIfNecessary<span class="br0"><font color="#663300">(</font></span>Session session, SessionFactory sessionFactory<span class="br0"><font color="#663300">)</font></span></div>
    </li>
    <li class="li1">
    <div class="de1">      <span class="kw2"><strong><font color="#7f0055">throws</font></strong></span> CleanupFailureDataAccessException <span class="br0"><font color="#663300">{</font></span></div>
    </li>
    <li class="li1">
    <div class="de1">    <span class="kw1"><font color="#b1b100">if</font></span> <span class="br0"><font color="#663300">(</font></span>session == <span class="kw2"><strong><font color="#7f0055">null</font></strong></span> || <br />
    TransactionSynchronizationManager.<span class="me1">hasResource</span><span class="br0"><font color="#663300">(</font></span>sessionFactory<font color="#663300"><span class="br0">)</span><span class="br0">)</span></font> <span class="br0"><font color="#663300">{</font></span></div>
    </li>
    <li class="li1">
    <div class="de1">      <span class="kw2"><strong><font color="#7f0055">return</font></strong></span>;</div>
    </li>
    <li class="li1">
    <div class="de1">    <span class="br0"><font color="#663300">}</font></span></div>
    </li>
    <li class="li1">
    <div class="de1">    logger.<span class="me1">debug</span><span class="br0"><font color="#663300">(</font></span><span class="st0"><font color="#0000ff">"Closing Hibernate session"</font></span><span class="br0"><font color="#663300">)</font></span>;</div>
    </li>
    <li class="li1">
    <div class="de1">    <span class="kw2"><strong><font color="#7f0055">try</font></strong></span> <span class="br0"><font color="#663300">{</font></span></div>
    </li>
    <li class="li1">
    <div class="de1">      session.<span class="me1">close</span><font color="#663300"><span class="br0">(</span><span class="br0">)</span></font>;</div>
    </li>
    <li class="li1">
    <div class="de1">    <span class="br0"><font color="#663300">}</font></span></div>
    </li>
    <li class="li1">
    <div class="de1">    <span class="kw2"><strong><font color="#7f0055">catch</font></strong></span> <span class="br0"><font color="#663300">(</font></span>JDBCException ex<span class="br0"><font color="#663300">)</font></span> <span class="br0"><font color="#663300">{</font></span></div>
    </li>
    <li class="li1">
    <div class="de1">      <span class="co1"><font color="#3f5fbf">// SQLException underneath</font></span></div>
    </li>
    <li class="li1">
    <div class="de1">      <span class="kw2"><strong><font color="#7f0055">throw</font></strong></span> <span class="kw2"><strong><font color="#7f0055">new</font></strong></span> CleanupFailureDataAccessException<span class="br0"><font color="#663300">(</font></span><span class="st0"><font color="#0000ff">"Could not close Hibernate session"</font></span>, ex.<span class="me1">getSQLException</span><font color="#663300"><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span></font>;</div>
    </li>
    <li class="li1">
    <div class="de1">    <span class="br0"><font color="#663300">}</font></span></div>
    </li>
    <li class="li1">
    <div class="de1">    <span class="kw2"><strong><font color="#7f0055">catch</font></strong></span> <span class="br0"><font color="#663300">(</font></span>HibernateException ex<span class="br0"><font color="#663300">)</font></span> <span class="br0"><font color="#663300">{</font></span></div>
    </li>
    <li class="li1">
    <div class="de1">      <span class="kw2"><strong><font color="#7f0055">throw</font></strong></span> <span class="kw2"><strong><font color="#7f0055">new</font></strong></span> CleanupFailureDataAccessException<span class="br0"><font color="#663300">(</font></span><span class="st0"><font color="#0000ff">"Could not close Hibernate session"</font></span>, ex<span class="br0"><font color="#663300">)</font></span>;</div>
    </li>
    <li class="li1">
    <div class="de1">    <span class="br0"><font color="#663300">}</font></span></div>
    </li>
    <li class="li1">
    <div class="de1">  <span class="br0"><font color="#663300">}</font></span> </div>
    </li>
</ol>
</pre>
<p>&nbsp;&nbsp;&nbsp;
也即是，如果有不是readOnly的transaction就可以由Flush.NEVER转为Flush.AUTO,拥有insert,
update,delete操作权限，如果没有transaction，并且没有另外人为地设flush
model的话，则doFilter的整个过程都是Flush.NEVER。所以受transaction保护的方法有写权限，没受保护的则没有。</p>
<pre class="xml">
<div class="head">采用spring的事务声明,使方法受transaction控制</div>
<ol>
    <li class="li1">
    <div class="de1"><span class="sc3"><span class="re1">&nbsp; &lt;bean id="baseTransaction" <br />
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; abstract="true"&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="transactionManager" ref="transactionManager"/&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="proxyTargetClass" value="true"/&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="transactionAttributes"&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;props&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;prop key="get*"&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;prop key="find*"&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;prop key="load*"&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;prop key="save*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;prop key="add*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;prop key="update*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;prop key="remove*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;/props&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &lt;/property&gt; <br />
    &nbsp; &nbsp; &lt;/bean&gt; </span></span><span class="sc3"><span class="re1"><br />
    </span></span></div>
    </li>
    <li class="li1">&nbsp; &nbsp; &lt;bean id="userService" parent="baseTransaction"&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="target"&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;bean class="com.phopesoft.security.service.impl.UserServiceImpl"/&gt; <br />
    &nbsp; &nbsp; &nbsp; &nbsp; &lt;/property&gt; <br />
    &nbsp; &nbsp; &lt;/bean&gt; </li>
</ol>
</pre>
</div>
<ol>&nbsp;</ol>
    <p>对
    于上例，则以save,add,update,remove开头的方法拥有可写的事务，如果当前有某个方法，如命名为importExcel()，则因没
    有transaction而没有写权限，这时若方法内有insert,update,delete操作的话，则需要手动设置flush
    model为Flush.AUTO,如</p>
    <pre class="java">
    <ol>
        <li class="li1">
        <div class="de1"> session.<span class="me1">setFlushMode</span><span class="br0"><font color="#663300">(</font></span>FlushMode.<span class="me1">AUTO</span><span class="br0"><font color="#663300">)</font></span>; </div>
        </li>
        <li class="li1">
        <div class="de1"> session.<span class="me1">save</span><span class="br0"><font color="#663300">(</font></span>user<span class="br0"><font color="#663300">)</font></span>; </div>
        </li>
        <li class="li1">
        <div class="de1"> session.<span class="me1">flush</span><font color="#663300"><span class="br0">(</span><span class="br0">)</span></font>; </div>
        </li>
    </ol>
    </pre>
    <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    尽管Open Session In
    View看起来还不错，其实副作用不少。看回上面OpenSessionInViewFilter的doFilterInternal方法代码，这个方法
    实际上是被父类的doFilter调用的，因此，我们可以大约了解的OpenSessionInViewFilter调用流程:
    request(请求)-&gt;open
    session并开始transaction-&gt;controller-&gt;View(Jsp)-&gt;结束transaction并
    close session.</p>
    <p>&nbsp;&nbsp;&nbsp;&nbsp;
    一切看起来很正确，尤其是在本地开发测试的时候没出现问题，但试想下如果流程中的某一步被阻塞的话，那在这期间connection就一直被占用而不释
    放。最有可能被阻塞的就是在写Jsp这步，一方面可能是页面内容大，response.write的时间长，另一方面可能是网速慢，服务器与用户间传输时
    间久。当大量这样的情况出现时，就有连接池连接不足，造成页面假死现象。</p>
    <p>Open Session In View是个双刃剑，放在公网上内容多流量大的网站请慎用。</p>
    </span></span>    &nbsp;<br />
    <br />
    <p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1441664</p>
<img src ="http://www.blogjava.net/hilor/aggbug/189346.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hilor/" target="_blank">hilor</a> 2008-03-28 20:29 <a href="http://www.blogjava.net/hilor/articles/189346.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>saveOrUpdate详解</title><link>http://www.blogjava.net/hilor/articles/165839.html</link><dc:creator>hilor</dc:creator><author>hilor</author><pubDate>Thu, 06 Dec 2007 08:49:00 GMT</pubDate><guid>http://www.blogjava.net/hilor/articles/165839.html</guid><wfw:comment>http://www.blogjava.net/hilor/comments/165839.html</wfw:comment><comments>http://www.blogjava.net/hilor/articles/165839.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hilor/comments/commentRss/165839.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hilor/services/trackbacks/165839.html</trackback:ping><description><![CDATA[<p>在Hibernate中，最核心的概念就是对PO的状态管理。一个PO有三种状态：</p>
<p>1、未被持久化的VO <br />
此时就是一个内存对象VO，由JVM管理生命周期</p>
<p>2、已被持久化的PO，并且在Session生命周期内 <br />
此时映射数据库数据，由数据库管理生命周期</p>
<p>3、曾被持久化过，但现在和Session已经detached了，以VO的身份在运行 <br />
这种和Session已经detached的PO还能够进入另一个Session，继续进行PO状态管理，此时它就成为PO的第二种状态了。<span style="color: red">这种PO实际上是跨了Session进行了状态维护的。</span></p>
<p>在传统的JDO1.x中，PO只有前面两种状态，一个PO一旦脱离PM，就丧失了状态了，不再和数据库数据关联，成为一个纯粹的内存VO，它即使进入一个新的PM，也不能恢复它的状态了。</p>
<p>Hibernate强的地方就在于，一个PO脱离Session之后，还能保持状态，再进入一个新的Session之后，就恢复状态管理的能力，但此时状态管理需要使用session.update或者session.saveOrUpdate，这就是Hibernate Reference中提到的&#8220;requires a slightly different programming model &#8221;</p>
<p>现在正式进入本话题：</p>
<p><span style="color: red">简单的来说，update和saveOrUpdate是用来对跨Session的PO进行状态管理的。</span></p>
<p>假设你的PO不需要跨Session的话，那么就不需要用到，例如你打开一个Session，对PO进行操作，然后关闭，之后这个PO你也不会再用到了，那么就不需要用update。</p>
<p>因此，我们来看看： <br />
<div class="code_title">代码</div>
<div class="code_div">
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-j">
    <li class="alt"><span><span>Foo&nbsp;foo=sess.load(Foo.</span><span class="keyword">class</span><span>,id);&nbsp; &nbsp;&nbsp;</span></span>
    <li class=""><span>foo.setXXX(xxx);&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>sess.flush(); &nbsp;&nbsp;</span>
    <li class=""><span>sess.commit();&nbsp;&nbsp;&nbsp;</span> </li>
</ol>
</div>
</div>
<script>render_code();</script>
<p>&nbsp;</p>
<p>PO对象foo的操作都在一个Session生命周期内完成，因此不需要显式的进行sess.update(foo)这样的操作。Hibernate会自动监测到foo对象已经被修改过，因此就向数据库发送一个update的sql。当然如果你非要加上sess.update(foo)也不会错，只不过这样做没有任何必要。</p>
<p>而跨Session的意思就是说这个PO对象在Session关闭之后，你还把它当做一个VO来用，后来你在Session外面又修改了它的属性，然后你又想打开一个Session，把VO的属性修改保存到数据库里面，那么你就需要用update了。</p>
<p>
<div class="code_title">代码</div>
<div class="code_div">
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-j">
    <li class="alt"><span><span class="comment">//&nbsp;in&nbsp;the&nbsp;first&nbsp;session&nbsp; </span><span>&nbsp;&nbsp;</span></span>
    <li class=""><span>Cat&nbsp;cat&nbsp;=&nbsp;(Cat)&nbsp;firstSession.load(Cat.</span><span class="keyword">class</span><span>,&nbsp;catId);&nbsp; &nbsp;&nbsp;</span></span>
    <li class="alt"><span>Cat&nbsp;potentialMate&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;Cat();&nbsp; &nbsp;&nbsp;</span></span>
    <li class=""><span>firstSession.save(potentialMate);&nbsp; &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;</span>
    <li class=""><span class="comment">//&nbsp;in&nbsp;a&nbsp;higher&nbsp;tier&nbsp;of&nbsp;the&nbsp;application&nbsp; </span><span>&nbsp;&nbsp;</span></span>
    <li class="alt"><span>cat.setMate(potentialMate);&nbsp; &nbsp;&nbsp;</span>
    <li class=""><span>&nbsp;&nbsp;</span>
    <li class="alt"><span class="comment">//&nbsp;later,&nbsp;in&nbsp;a&nbsp;new&nbsp;session&nbsp; </span><span>&nbsp;&nbsp;</span></span>
    <li class=""><span>secondSession.update(cat);&nbsp;&nbsp;</span><span class="comment">//&nbsp;update&nbsp;cat&nbsp; </span><span>&nbsp;&nbsp;</span></span>
    <li class="alt"><span>secondSession.update(mate);&nbsp;</span><span class="comment">//&nbsp;update&nbsp;mate</span><span>&nbsp;&nbsp;</span></span> </li>
</ol>
</div>
</div>
<script>render_code();</script>
<p>&nbsp;</p>
<p>cat和mate对象是在第一个session中取得的，在第一个session关闭之后，他们就成了PO的第三种状态，和Session已经detached的PO，此时他们的状态信息仍然被保留下来了。当他们进入第二个session之后，立刻就可以进行状态的更新。但是由于对cat的修改操作：cat.setMate(potentialMate); 是在Session外面进行的，Hibernate不可能知道cat对象已经被改过了，第二个Session并不知道这种修改，因此一定要显式的调用secondSession.update(cat); 通知Hibernate，cat对象已经修改了，你必须发送update的sql了。</p>
<p>所以update的作用就在于此，它只会被用于当一个PO对象跨Session进行状态同步的时候才需要写。而一个PO对象当它不需要跨Session进行状态管理的时候，是不需要写update的。</p>
<p>再谈谈saveOrUpdate的用场： <br />
<br />
saveOrUpdate和update的区别就在于在跨Session的PO状态管理中，Hibernate对PO采取何种策略。</p>
<p>例如当你写一个DAOImpl的时候，让cat对象增加一个mate，如下定义： <br />
<div class="code_title">代码</div>
<div class="code_div">
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-j">
    <li class="alt"><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;addMate(Cat&nbsp;cat,&nbsp;Mate&nbsp;mate)&nbsp;{ &nbsp;&nbsp;</span></span>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;Session&nbsp;session&nbsp;=&nbsp;...; &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;Transacton&nbsp;tx&nbsp;=&nbsp;...; &nbsp;&nbsp;</span>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;session.update(cat); &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;cat.addMate(mate); &nbsp;&nbsp;</span>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;tx.commit(); &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;session.close(); &nbsp;&nbsp;</span>
    <li class=""><span>};&nbsp;&nbsp;</span> </li>
</ol>
</div>
</div>
<script>render_code();</script>
<p>&nbsp;</p>
<p>显然你是需要把Hibernate的操作封装在DAO里面的，让业务层的程序员和Web层的程序员不需要了解Hibernate，直接对DAO进行调用。</p>
<p>此时问题就来了：上面的代码运行正确有一个必要的前提，那就是方法调用参数cat对象必须是一个已经被持久化过的PO，也就是来说，它应该首先从数据库查询出来，然后才能这样用。但是业务层的程序员显然不知道这种内部的玄妙，如果他的业务是现在增加一个cat，然后再增加它的mate，他显然会这样调用，new一个cat对象出来，然后就addMate：</p>
<p>
<div class="code_title">代码</div>
<div class="code_div">
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-j">
    <li class="alt"><span><span>Cat&nbsp;cat&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;Cat(); &nbsp;&nbsp;</span></span>
    <li class=""><span>cat.setXXX(); &nbsp;&nbsp;</span>
    <li class="alt"><span>daoimpl.addMate(cat,mate);&nbsp;&nbsp;</span> </li>
</ol>
</div>
</div>
<script>render_code();</script>
<p>&nbsp;</p>
<p>但是请注意看，这个cat对象只是一个VO，它没有被持久化过，它还不是PO，它没有资格调用addMate方法，因此调用addMate方法不会真正往数据库里面发送update的sql，这个cat对象必须先被save到数据库，在真正成为一个PO之后，才具备addMate的资格。</p>
<p>你必须这样来操作：</p>
<p>
<div class="code_title">代码</div>
<div class="code_div">
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-j">
    <li class="alt"><span><span>Cat&nbsp;cat&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;Cat(); &nbsp;&nbsp;</span></span>
    <li class=""><span>cat.setXXX(); &nbsp;&nbsp;</span>
    <li class="alt"><span>daoimpl.addCat(cat); &nbsp;&nbsp;</span>
    <li class=""><span>daoimpl.addMate(cat,&nbsp;mate);&nbsp;&nbsp;</span> </li>
</ol>
</div>
</div>
<script>render_code();</script>
<p>&nbsp;</p>
<p>先持久化cat，然后才能对cat进行其他的持久化操作。因此要求业务层的程序员必须清楚cat对象处于何种状态，到底是第一种，还是第三种。如果是第一种，就要先save，再addMate；如果是第三种，就直接addMate。</p>
<p>但是最致命的是，如果整个软件分层很多，业务层的程序员他拿到这个cat对象也可能是上层Web应用层传递过来的cat，他自己也不知道这个cat究竟是VO，没有被持久化过，还是已经被持久化过，那么他根本就没有办法写程序了。</p>
<p>所以这样的DAOImpl显然是有问题的，它会对业务层的程序员造成很多编程上的陷阱，业务层的程序员必须深刻的了解他调用的每个DAO对PO对象进行了何种状态管理，必须深刻的了解他的PO对象在任何时候处于什么确切的状态，才能保证编程的正确性，显然这是做不到的，但是有了saveOrUpdate，这些问题就迎刃而解了。</p>
<p>现在你需要修改addMate方法：</p>
<p>
<div class="code_title">代码</div>
<div class="code_div">
<div class="dp-highlighter">
<div class="bar"></div>
<ol class="dp-j">
    <li class="alt"><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;addMate(Cat&nbsp;cat,&nbsp;Mate&nbsp;mate)&nbsp;{ &nbsp;&nbsp;</span></span>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;Session&nbsp;session&nbsp;=&nbsp;...; &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;Transacton&nbsp;tx&nbsp;=&nbsp;...; &nbsp;&nbsp;</span>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;session.saveOrUpdate(cat); &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;cat.addMate(mate); &nbsp;&nbsp;</span>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;tx.commit(); &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;session.close(); &nbsp;&nbsp;</span>
    <li class=""><span>};&nbsp;&nbsp;</span> </li>
</ol>
</div>
</div>
<script>render_code();</script>
<p>&nbsp;</p>
<p>如上，如果业务层的程序员传进来的是一个已经持久化过的PO对象，那么Hibernate会更新cat对象(假设业务层的程序员在Session外面修改过cat的属性)，如果传进来的是一个新new出来的对象，那么向数据库save这个PO对象。</p>
<p>BTW: Hibernate此时究竟采取更新cat对象，还是save cat对象，取决于unsave-value的设定。</p>
<p>这样，业务层的程序员就不必再操心PO的状态问题了，对于他们来说，不管cat是new出来的对象，只是一个VO也好；还是从数据库查询出来的的PO对象也好，全部都是直接addMate就OK了：</p>
<p>
<div class="code_title">代码</div>
<div class="code_div">
<div class="dp-highlighter">
<ol class="dp-j">
    <li class="alt"><span><span>daoimple.addMate(cat,&nbsp;mate);&nbsp;&nbsp;</span></span> </li>
</ol>
</div>
</div>
<script>render_code();</script>
<p>&nbsp;</p>
<p>这便是saveOrUpdate的作用。<br />
<br />
Robbin老大的精华.. <a href="http://www.javaeye.com/topic/2712?page=1">http://www.javaeye.com/topic/2712?page=1</a></p>
<img src ="http://www.blogjava.net/hilor/aggbug/165839.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hilor/" target="_blank">hilor</a> 2007-12-06 16:49 <a href="http://www.blogjava.net/hilor/articles/165839.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>