??xml version="1.0" encoding="utf-8" standalone="yes"?>日韩三级电影视频,99热国内精品永久免费观看,久久久久青草大香线综合精品http://www.aygfsteel.com/hilor/category/25040.html我的学习案?/description>zh-cnSun, 30 Mar 2008 16:36:00 GMTSun, 30 Mar 2008 16:36:00 GMT60关于OpenSessionInViewhttp://www.aygfsteel.com/hilor/articles/189348.htmlhilorhilorFri, 28 Mar 2008 12:38:00 GMThttp://www.aygfsteel.com/hilor/articles/189348.htmlhttp://www.aygfsteel.com/hilor/comments/189348.htmlhttp://www.aygfsteel.com/hilor/articles/189348.html#Feedback0http://www.aygfsteel.com/hilor/comments/commentRss/189348.htmlhttp://www.aygfsteel.com/hilor/services/trackbacks/189348.html OpenSessionInViewFilter讨论
Hibernate的Lazy初始?:n关系Ӟ你必M证是在同一个Session内部使用q个关系集合Q不然Hiernate抛Z外?

另外Q你不愿意你的DAO试代码每次都打开关系SessionQ因此,我们一般会采用OpenSessionInView模式?

OpenSessionInViewFilter解决Web应用E序的问?

如果E序是在正常的WebE序中运行,那么Spring?strong style="color: black; background-color: #ffff66;">OpenSessionInViewFilter能够解决问题Q它Q?
protected void doFilterInternal(HttpServletRequest request, 
HttpServletResponse response,
       FilterChain filterChain) throws ServletException, IOException {
      SessionFactory sessionFactory = lookupSessionFactory();
      logger.debug("Opening Hibernate Session in OpenSessionInViewFilter");
      Session session = getSession(sessionFactory);
      TransactionSynchronizationManager.bindResource(sessionFactory,
new SessionHolder(session));
      try {
            filterChain.doFilter(request, response);
      }
      finally {
            TransactionSynchronizationManager.unbindResource(sessionFactory);
            logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
            closeSession(session, sessionFactory);
      }
}
可以看到Q这个Filter在request开始之前,把sessionFactoryl定到TransactionSynchronizationManagerQ和q个SessionHolder相关。这个意味着所有request执行q程中将使用q个session。而在hl束后,和q个sessionFactory对应的session解绑Qƈ且关闭Session?

Z么绑定以后,可以防止每ơ不会新开一个Session呢?看看HibernateDaoSupport的情况:

public final void setSessionFactory(SessionFactory sessionFactory) {
this.hibernateTemplate = new HibernateTemplate(sessionFactory);
}
protected final HibernateTemplate getHibernateTemplate() {
return hibernateTemplate;
}

我们的DAO用这个templateq行操作Q?

public abstract class BaseHibernateObjectDao
      extends HibernateDaoSupport
      implements BaseObjectDao {


      protected BaseEntityObject getByClassId(final long id) {
            BaseEntityObject obj =
                  (BaseEntityObject) getHibernateTemplate()
                        .execute(new HibernateCallback() {


                  public Object doInHibernate(Session session)
                        throws HibernateException {
                        return session.get(getPersistentClass(),
new Long(id));
                  }


            });
            return obj;
      }



      public void save(BaseEntityObject entity) {
            getHibernateTemplate().saveOrUpdate(entity);
      }


      public void remove(BaseEntityObject entity) {
            try {


                  getHibernateTemplate().delete(entity);
            } catch (Exception e) {
                  throw new FlexEnterpriseDataAccessException(e);
            }
      }


      public void refresh(final BaseEntityObject entity) {
            getHibernateTemplate().execute(new HibernateCallback() {


                  public Object doInHibernate(Session session)
                        throws HibernateException {
                        session.refresh(entity);
                        return null;
                  }


            });
      }


      public void replicate(final Object entity) {
            getHibernateTemplate().execute(new HibernateCallback() {


                  public Object doInHibernate(Session session)
                        throws HibernateException {
                        session.replicate(entity,
ReplicationMode.OVERWRITE);
                        return null;
                  }


            });
      }

而HibernateTemplate试图每次在execute之前去获得SessionQ执行完力争关闭Session
public Object execute(HibernateCallback action) throws DataAccessException {
      Session session = (!this.allowCreate ?
            SessionFactoryUtils.getSession(getSessionFactory(),
false) :
            SessionFactoryUtils.getSession(getSessionFactory(),
getEntityInterceptor(),
getJdbcExceptionTranslator()));
      boolean existingTransaction =
TransactionSynchronizationManager.hasResource(getSessionFactory());
      if (!existingTransaction && getFlushMode() == FLUSH_NEVER) {
            session.setFlushMode(FlushMode.NEVER);
      }
      try {
            Object result = action.doInHibernate(session);
            flushIfNecessary(session, existingTransaction);
            return result;
      }
      catch (HibernateException ex) {
            throw convertHibernateAccessException(ex);
      }
      catch (SQLException ex) {
            throw convertJdbcAccessException(ex);
      }
      catch (RuntimeException ex) {
            // callback code threw application exception
            throw ex;
      }
      finally {
            SessionFactoryUtils.closeSessionIfNecessary(
session, getSessionFactory());
      }
}
而这个SessionFactoryUtils能否得到当前的session以及closeSessionIfNecessary是否真正关闭sessionQ端取决于这个session是否用sessionHolder和这个sessionFactory在我们最开始提到的TransactionSynchronizationManagerl定?
public static void closeSessionIfNecessary(Session session, 
SessionFactory sessionFactory)
throws CleanupFailureDataAccessException {
      if (session == null ||
       TransactionSynchronizationManager.hasResource(sessionFactory)) {
            return;
      }
      logger.debug("Closing Hibernate session");
      try {
            session.close();
      }
      catch (JDBCException ex) {
            // SQLException underneath
            throw new CleanupFailureDataAccessException(
            "Cannot close Hibernate session", ex.getSQLException());
      }
      catch (HibernateException ex) {
            throw new CleanupFailureDataAccessException(
            "Cannot close Hibernate session", ex);
      }
}

HibernateInterceptor和OpenSessionInViewInterceptor的问?

使用同样的方法,q两个Interceptor可以用来解决问题。但是关键的不同之处在于Q它们的力度只能定义在DAO或业务方法上Q而不是在我们的TestҎ上,除非我们把它们应用到TestCase的方法上Q但你不大可能ؓTestCased义一个接口,然后把Interceptor应用到这个接口的某些Ҏ上。直接用HibernateTransactionManager也是一L。因此,如果我们有这L试Q?

Category parentCategory  = new Category ();
      parentCategory.setName("parent");
      dao.save(parentCategory);

      Category childCategory = new Category();
childCategory.setName("child");


      parentCategory.addChild(childCategory);
      dao.save(childCategory);


      Category savedParent = dao.getCategory("parent");
      Category savedChild = (Category ) savedParent.getChildren().get(0);
      assertEquals(savedChild, childCategory);

意味着两g事情Q?
  • 每次DAO执行都会启动一个session和关闭一个session
  • 如果我们定义了一个lazy的关p,那么最后的Category savedChild = (Category ) savedParent.getChildren().get(0);会让hibernate报错?

解决Ҏ

一U方法是对TestCase应用Interceptor或者TransactionManagerQ但q个恐怕会造成很多ȝ。除非是使用增强方式的AOP.我前期采用这U方?Aspectwerkz)Q在Eclipse里面也跑得含好?

另一U方法是在TestCase的setup和teardown里面实现和Filter完全一L处理Q其他的TestCase都从q个TestCasel承Q这U方法是我目前所使用的?



hilor 2008-03-28 20:38 发表评论
]]>
open session in view 的?/title><link>http://www.aygfsteel.com/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.aygfsteel.com/hilor/articles/189346.html</guid><wfw:comment>http://www.aygfsteel.com/hilor/comments/189346.html</wfw:comment><comments>http://www.aygfsteel.com/hilor/articles/189346.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/hilor/comments/commentRss/189346.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/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: 宋体;">关闭Q所?/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: 宋体;">的话Q要在应用层内把关系集合都初始化Q如</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;"> company.getEmployees()</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">Q否?/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;">    Open Session In View</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">提供了一U简便的ҎQ较好地解决?/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: 宋体;">    </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" ><strong><font color="#78a515">SpringSide</font></strong></a>)</span></span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">Q功能相同,只是一个在</span><span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana;">web.xml</span><span style="font-size: 10pt; color: #4b4b4b; font-family: 宋体;">配置Q另一个在</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;">    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: 宋体;">l定到当?/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: 宋体;">的整个期间都可以使用Q如?/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: 宋体;">数据Q如</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 id="wmqeeuq" class="head"> <pre class="java"> <div id="wmqeeuq" class="head">OpenSessionInViewInterceptor配置</div> <ol> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"><beans> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <bean name=<span id="wmqeeuq" class="st0"><font color="#0000ff">"openSessionInViewInterceptor"</font></span> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"><span id="wmqeeuq" class="kw2"><strong><font color="#7f0055">class</font></strong></span>=<span id="wmqeeuq" class="st0"><font color="#0000ff">"org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor"</font></span>> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <property name=<span id="wmqeeuq" class="st0"><font color="#0000ff">"sessionFactory"</font></span>></div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <ref bean=<span id="wmqeeuq" class="st0"><font color="#0000ff">"sessionFactory"</font></span>/></div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> </property> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> </bean> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <bean id=<span id="wmqeeuq" class="st0"><font color="#0000ff">"urlMapping"</font></span> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"><span id="wmqeeuq" class="kw2"><strong><font color="#7f0055">class</font></strong></span>=<span id="wmqeeuq" class="st0"><font color="#0000ff">"org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"</font></span>> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <property name=<span id="wmqeeuq" class="st0"><font color="#0000ff">"interceptors"</font></span>> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <list> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <ref bean=<span id="wmqeeuq" class="st0"><font color="#0000ff">"openSessionInViewInterceptor"</font></span>/> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> </list> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> </property> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <property name=<span id="wmqeeuq" class="st0"><font color="#0000ff">"mappings"</font></span>> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> ... </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> </property> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> </bean> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1">... </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"></beans> </div> </li> </ol> </pre> </div> <div id="wmqeeuq" class="head"> <pre class="java"> <div id="wmqeeuq" class="head">OpenSessionInViewFilter配置</div> <ol> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"><web-app> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1">... </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <filter> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <filter-name>hibernateFilter</filter-name> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <filter-class> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> org.<span id="wmqeeuq" class="me1">springframework</span>.<span id="wmqeeuq" class="me1">orm</span>.<span id="wmqeeuq" class="me1">hibernate3</span>.<span id="wmqeeuq" class="me1">support</span>.<span id="wmqeeuq" class="me1">OpenSessionInViewFilter</span> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> </filter-class> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <!-- singleSession默认为true,若设为false则等于没?span class="me1">OpenSessionInView --></span></div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <init-param> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <param-name>singleSession</param-name> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <param-value>true</param-value></div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> </init-param></div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> </filter> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1">... </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <filter-mapping> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <filter-name>hibernateFilter</filter-name> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <url-pattern>*.<span id="wmqeeuq" class="me1">do</span></url-pattern> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> </filter-mapping> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1">... </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"></web-app> </div> </li> </ol> </pre> <p>很多人在使用OpenSessionInViewq程中提及一个错误:</p> <pre class="java"> <ol> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1">org.<span id="wmqeeuq" class="me1">springframework</span>.<span id="wmqeeuq" class="me1">dao</span>.<span id="wmqeeuq" class="me1">InvalidDataAccessApiUsageException</span>: Write operations </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1">are not allowed in read-only mode <span id="wmqeeuq" class="br0"><font color="#663300">(</font></span>FlushMode.<span id="wmqeeuq" class="me1">NEVER</span><span id="wmqeeuq" class="br0"><font color="#663300">)</font></span> - turn your Session into </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1">FlushMode.<span id="wmqeeuq" class="me1">AUTO</span> or remove <span id="wmqeeuq" class="st0"><font color="#0000ff">'readOnly'</font></span> marker from transaction definition </div> </li> </ol> </pre> <p>看看OpenSessionInViewFilter里的几个Ҏ</p> <pre class="java"> <ol> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"><span id="wmqeeuq" class="kw2"><strong><font color="#7f0055">protected</font></strong></span> <span id="wmqeeuq" class="kw4"><font color="#f63333">void</font></span> doFilterInternal<span id="wmqeeuq" class="br0"><font color="#663300">(</font></span>HttpServletRequest request, <br /> HttpServletResponse response,FilterChain filterChain<span id="wmqeeuq" class="br0"><font color="#663300">)</font></span> <br /> <span id="wmqeeuq" class="kw2"><strong><font color="#7f0055">throws</font></strong></span> ServletException, <span id="wmqeeuq" class="kw3"><font color="#ff0000">IOException</font></span> <span id="wmqeeuq" class="br0"><font color="#663300">{<br /> </font></span> SessionFactory sessionFactory = lookupSessionFactory<font color="#663300"><span id="wmqeeuq" class="br0">(</span><span id="wmqeeuq" class="br0">)</span></font>;<br /> logger.<span id="wmqeeuq" class="me1">debug</span><span id="wmqeeuq" class="br0"><font color="#663300">(</font></span><span id="wmqeeuq" class="st0"><font color="#0000ff">"Opening Hibernate Session in OpenSessionInViewFilter"</font></span><span id="wmqeeuq" class="br0"><font color="#663300">)</font></span>;<br /> Session session = getSession<span id="wmqeeuq" class="br0"><font color="#663300">(</font></span>sessionFactory<span id="wmqeeuq" class="br0"><font color="#663300">)</font></span>;<br /> TransactionSynchronizationManager.<span id="wmqeeuq" class="me1">bindResource</span><span id="wmqeeuq" class="br0"><font color="#663300">(<br /> </font></span>  sessionFactory, <span id="wmqeeuq" class="kw2"><strong><font color="#7f0055">new</font></strong></span> SessionHolder<span id="wmqeeuq" class="br0"><font color="#663300">(</font></span>session<font color="#663300"><span id="wmqeeuq" class="br0">)</span><span id="wmqeeuq" class="br0">)</span></font>;<br /> <span id="wmqeeuq" class="kw2"><strong><font color="#7f0055">try</font></strong></span> <span id="wmqeeuq" class="br0"><font color="#663300">{<br /> </font></span>  filterChain.<span id="wmqeeuq" class="me1">doFilter</span><span id="wmqeeuq" class="br0"><font color="#663300">(</font></span>request, response<span id="wmqeeuq" class="br0"><font color="#663300">)</font></span>;<br /> <span id="wmqeeuq" class="br0"><font color="#663300">}<br /> </font></span><span id="wmqeeuq" class="kw2"><strong><font color="#7f0055"> finally</font></strong></span> <span id="wmqeeuq" class="br0"><font color="#663300">{<br /> </font></span> TransactionSynchronizationManager.<span id="wmqeeuq" class="me1">unbindResource</span><span id="wmqeeuq" class="br0"><font color="#663300">(</font></span>sessionFactory<span id="wmqeeuq" class="br0"><font color="#663300">)</font></span>;<br /> logger.<span id="wmqeeuq" class="me1">debug</span><span id="wmqeeuq" class="br0"><font color="#663300">(</font></span><span id="wmqeeuq" class="st0"><font color="#0000ff">"Closing Hibernate Session in OpenSessionInViewFilter"</font></span><span id="wmqeeuq" class="br0"><font color="#663300">)</font></span>;<br /> closeSession<span id="wmqeeuq" class="br0"><font color="#663300">(</font></span>session, sessionFactory<span id="wmqeeuq" class="br0"><font color="#663300">)</font></span>;<br /> <font color="#663300"><span id="wmqeeuq" class="br0">}<br /> </span><span id="wmqeeuq" class="br0">}</span></font><span id="wmqeeuq" class="br0"><br /> <br /> <br /> <br /> <br /> </span> </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"><span id="wmqeeuq" class="kw2"><strong><font color="#7f0055">protected</font></strong></span> Session getSession<span id="wmqeeuq" class="br0"><font color="#663300">(</font></span>SessionFactory sessionFactory<span id="wmqeeuq" class="br0"><font color="#663300">)<br /> </font></span><span id="wmqeeuq" class="kw2"><strong><font color="#7f0055">throws</font></strong></span> DataAccessResourceFailureException <span id="wmqeeuq" class="br0"><font color="#663300">{<br /> </font></span> Session session = SessionFactoryUtils.<span id="wmqeeuq" class="me1">getSession</span><span id="wmqeeuq" class="br0"><font color="#663300">(</font></span>sessionFactory, <span id="wmqeeuq" class="kw2"><strong><font color="#7f0055">true</font></strong></span><span id="wmqeeuq" class="br0"><font color="#663300">)</font></span>;<br /> session.<span id="wmqeeuq" class="me1">setFlushMode</span><span id="wmqeeuq" class="br0"><font color="#663300">(</font></span>FlushMode.<span id="wmqeeuq" class="me1">NEVER</span><span id="wmqeeuq" class="br0"><font color="#663300">)</font></span>;<br /> <span id="wmqeeuq" class="kw2"><strong><font color="#7f0055">return</font></strong></span> session;<br /> <span id="wmqeeuq" class="br0"><font color="#663300">}</font></span></div> </li> <li id="wmqeeuq" class="li1"><span id="wmqeeuq" class="kw2"><br /> <strong><font color="#7f0055">protected</font></strong></span> <span id="wmqeeuq" class="kw4"><font color="#f63333">void</font></span> closeSession<span id="wmqeeuq" class="br0"><font color="#663300">(</font></span>Session session, SessionFactory sessionFactory<span id="wmqeeuq" class="br0"><font color="#663300">)<br /> </font></span><span id="wmqeeuq" class="kw2"><strong><font color="#7f0055">throws</font></strong></span> CleanupFailureDataAccessException <span id="wmqeeuq" class="br0"><font color="#663300">{<br /> </font></span> SessionFactoryUtils.<span id="wmqeeuq" class="me1">closeSessionIfNecessary</span><span id="wmqeeuq" class="br0"><font color="#663300">(</font></span>session, sessionFactory<span id="wmqeeuq" class="br0"><font color="#663300">)</font></span>;<br /> <span id="wmqeeuq" class="br0"><font color="#663300">}</font></span> </li> </ol> </pre> <p>     可以看到OpenSessionInViewFilter在getSession的时?会把获取回来的session的flush mode 设ؓFlushMode.NEVER。然后把该sessionFactoryl定? TransactionSynchronizationManagerQrequest的整个过E都使用同一个sessionQ在hq后再接除该 sessionFactory的绑定,最?span class="me1">closeSessionIfNecessary</span>Ҏ? session是否已和transactionl定来决定是否关闭session。在q个q程中,若HibernateTemplate 发现自当前session有不是readOnly的transactionQ就会获取到FlushMode.AUTO SessionQҎ拥有写权限?/p> <pre class="java"> <ol> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"><span id="wmqeeuq" class="kw2"><strong><font color="#7f0055">public</font></strong></span> <span id="wmqeeuq" class="kw2"><strong><font color="#7f0055">static</font></strong></span> <span id="wmqeeuq" class="kw4"><font color="#f63333">void</font></span> closeSessionIfNecessary<span id="wmqeeuq" class="br0"><font color="#663300">(</font></span>Session session, SessionFactory sessionFactory<span id="wmqeeuq" class="br0"><font color="#663300">)</font></span></div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <span id="wmqeeuq" class="kw2"><strong><font color="#7f0055">throws</font></strong></span> CleanupFailureDataAccessException <span id="wmqeeuq" class="br0"><font color="#663300">{</font></span></div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <span id="wmqeeuq" class="kw1"><font color="#b1b100">if</font></span> <span id="wmqeeuq" class="br0"><font color="#663300">(</font></span>session == <span id="wmqeeuq" class="kw2"><strong><font color="#7f0055">null</font></strong></span> || <br /> TransactionSynchronizationManager.<span id="wmqeeuq" class="me1">hasResource</span><span id="wmqeeuq" class="br0"><font color="#663300">(</font></span>sessionFactory<font color="#663300"><span id="wmqeeuq" class="br0">)</span><span id="wmqeeuq" class="br0">)</span></font> <span id="wmqeeuq" class="br0"><font color="#663300">{</font></span></div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <span id="wmqeeuq" class="kw2"><strong><font color="#7f0055">return</font></strong></span>;</div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <span id="wmqeeuq" class="br0"><font color="#663300">}</font></span></div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> logger.<span id="wmqeeuq" class="me1">debug</span><span id="wmqeeuq" class="br0"><font color="#663300">(</font></span><span id="wmqeeuq" class="st0"><font color="#0000ff">"Closing Hibernate session"</font></span><span id="wmqeeuq" class="br0"><font color="#663300">)</font></span>;</div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <span id="wmqeeuq" class="kw2"><strong><font color="#7f0055">try</font></strong></span> <span id="wmqeeuq" class="br0"><font color="#663300">{</font></span></div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> session.<span id="wmqeeuq" class="me1">close</span><font color="#663300"><span id="wmqeeuq" class="br0">(</span><span id="wmqeeuq" class="br0">)</span></font>;</div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <span id="wmqeeuq" class="br0"><font color="#663300">}</font></span></div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <span id="wmqeeuq" class="kw2"><strong><font color="#7f0055">catch</font></strong></span> <span id="wmqeeuq" class="br0"><font color="#663300">(</font></span>JDBCException ex<span id="wmqeeuq" class="br0"><font color="#663300">)</font></span> <span id="wmqeeuq" class="br0"><font color="#663300">{</font></span></div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <span id="wmqeeuq" class="co1"><font color="#3f5fbf">// SQLException underneath</font></span></div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <span id="wmqeeuq" class="kw2"><strong><font color="#7f0055">throw</font></strong></span> <span id="wmqeeuq" class="kw2"><strong><font color="#7f0055">new</font></strong></span> CleanupFailureDataAccessException<span id="wmqeeuq" class="br0"><font color="#663300">(</font></span><span id="wmqeeuq" class="st0"><font color="#0000ff">"Could not close Hibernate session"</font></span>, ex.<span id="wmqeeuq" class="me1">getSQLException</span><font color="#663300"><span id="wmqeeuq" class="br0">(</span><span id="wmqeeuq" class="br0">)</span><span id="wmqeeuq" class="br0">)</span></font>;</div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <span id="wmqeeuq" class="br0"><font color="#663300">}</font></span></div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <span id="wmqeeuq" class="kw2"><strong><font color="#7f0055">catch</font></strong></span> <span id="wmqeeuq" class="br0"><font color="#663300">(</font></span>HibernateException ex<span id="wmqeeuq" class="br0"><font color="#663300">)</font></span> <span id="wmqeeuq" class="br0"><font color="#663300">{</font></span></div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <span id="wmqeeuq" class="kw2"><strong><font color="#7f0055">throw</font></strong></span> <span id="wmqeeuq" class="kw2"><strong><font color="#7f0055">new</font></strong></span> CleanupFailureDataAccessException<span id="wmqeeuq" class="br0"><font color="#663300">(</font></span><span id="wmqeeuq" class="st0"><font color="#0000ff">"Could not close Hibernate session"</font></span>, ex<span id="wmqeeuq" class="br0"><font color="#663300">)</font></span>;</div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <span id="wmqeeuq" class="br0"><font color="#663300">}</font></span></div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> <span id="wmqeeuq" class="br0"><font color="#663300">}</font></span> </div> </li> </ol> </pre> <p>    也即是,如果有不是readOnly的transaction可以由Flush.NEVER转ؓFlush.AUTO,拥有insert, update,delete操作权限Q如果没有transactionQƈ且没有另外h为地设flush model的话Q则doFilter的整个过E都是Flush.NEVER。所以受transaction保护的方法有写权限,没受保护的则没有?/p> <pre class="xml"> <div id="wmqeeuq" class="head">采用spring的事务声?使方法受transaction控制</div> <ol> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"><span id="wmqeeuq" class="sc3"><span id="wmqeeuq" class="re1">  <bean id="baseTransaction" <br /> class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" <br />           abstract="true"> <br />         <property name="transactionManager" ref="transactionManager"/> <br />         <property name="proxyTargetClass" value="true"/> <br />         <property name="transactionAttributes"> <br />             <props> <br />                 <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop> <br />                 <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop> <br />                 <prop key="load*">PROPAGATION_REQUIRED,readOnly</prop> <br />                 <prop key="save*">PROPAGATION_REQUIRED</prop> <br />                 <prop key="add*">PROPAGATION_REQUIRED</prop> <br />                 <prop key="update*">PROPAGATION_REQUIRED</prop> <br />                 <prop key="remove*">PROPAGATION_REQUIRED</prop> <br />             </props> <br />         </property> <br />     </bean> </span></span><span id="wmqeeuq" class="sc3"><span id="wmqeeuq" class="re1"><br /> </span></span></div> </li> <li id="wmqeeuq" class="li1">    <bean id="userService" parent="baseTransaction"> <br />         <property name="target"> <br />             <bean class="com.phopesoft.security.service.impl.UserServiceImpl"/> <br />         </property> <br />     </bean> </li> </ol> </pre> </div> <ol> </ol> <p>? 于上例,则以save,add,update,remove开头的Ҏ拥有可写的事务,如果当前有某个方法,如命名ؓimportExcel()Q则因没 有transaction而没有写权限Q这时若Ҏ内有insert,update,delete操作的话Q则需要手动设|flush model为Flush.AUTO,?/p> <pre class="java"> <ol> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> session.<span id="wmqeeuq" class="me1">setFlushMode</span><span id="wmqeeuq" class="br0"><font color="#663300">(</font></span>FlushMode.<span id="wmqeeuq" class="me1">AUTO</span><span id="wmqeeuq" class="br0"><font color="#663300">)</font></span>; </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> session.<span id="wmqeeuq" class="me1">save</span><span id="wmqeeuq" class="br0"><font color="#663300">(</font></span>user<span id="wmqeeuq" class="br0"><font color="#663300">)</font></span>; </div> </li> <li id="wmqeeuq" class="li1"> <div id="wmqeeuq" class="de1"> session.<span id="wmqeeuq" class="me1">flush</span><font color="#663300"><span id="wmqeeuq" class="br0">(</span><span id="wmqeeuq" class="br0">)</span></font>; </div> </li> </ol> </pre> <p>      管Open Session In View看v来还不错Q其实副作用不少。看回上面OpenSessionInViewFilter的doFilterInternalҎ代码Q这个方? 实际上是被父cȝdoFilter调用的,因此Q我们可以大U了解的OpenSessionInViewFilter调用程: request(h)->open sessionq开始transaction->controller->View(Jsp)->l束transactionq? close session.</p> <p>     一切看h很正,其是在本地开发测试的时候没出现问题Q但试想下如果流E中的某一步被d的话Q那在这期间connection׃直被占用而不? 放。最有可能被d的就是在写Jspq步Q一斚w可能是页面内容大Qresponse.write的时间长Q另一斚w可能是网速慢Q服务器与用户间传输? 间久。当大量q样的情况出现时Q就有连接池q接不Q造成面假死现象?/p> <p>Open Session In View是个双刃剑,攑֜公网上内容多量大的|站h用?/p> </span></span>  <br /> <br /> <p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1441664</p> <img src ="http://www.aygfsteel.com/hilor/aggbug/189346.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/hilor/" target="_blank">hilor</a> 2008-03-28 20:29 <a href="http://www.aygfsteel.com/hilor/articles/189346.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>saveOrUpdate详解http://www.aygfsteel.com/hilor/articles/165839.htmlhilorhilorThu, 06 Dec 2007 08:49:00 GMThttp://www.aygfsteel.com/hilor/articles/165839.htmlhttp://www.aygfsteel.com/hilor/comments/165839.htmlhttp://www.aygfsteel.com/hilor/articles/165839.html#Feedback0http://www.aygfsteel.com/hilor/comments/commentRss/165839.htmlhttp://www.aygfsteel.com/hilor/services/trackbacks/165839.html在Hibernate中,最核心的概念就是对PO的状态管理。一个PO有三U状态:

1、未被持久化的VO
此时是一个内存对象VOQ由JVM理生命周期

2、已被持久化的POQƈ且在Session生命周期?
此时映射数据库数据,由数据库理生命周期

3、曾被持久化q,但现在和Session已经detached了,以VO的n份在q行
q种和Session已经detached的POq能够进入另一个SessionQl进行PO状态管理,此时它就成ؓPO的第二种状态了?span style="color: red">q种PO实际上是跨了Sessionq行了状态维护的?/span>

在传l的JDO1.x中,PO只有前面两种状态,一个PO一旦脱PMQ就丧失了状态了Q不再和数据库数据关联,成ؓ一个纯_的内存VOQ它即ɘq入一个新的PMQ也不能恢复它的状态了?/p>

Hibernate强的地方在于,一个POqSession之后Q还能保持状态,再进入一个新的Session之后Q就恢复状态管理的能力Q但此时状态管理需要用session.update或者session.saveOrUpdateQ这是Hibernate Reference中提到的“requires a slightly different programming model ”

现在正式q入本话题:

单的来说Qupdate和saveOrUpdate是用来对跨Session的POq行状态管理的?/span>

假设你的PO不需要跨Session的话Q那么就不需要用刎ͼ例如你打开一个SessionQ对POq行操作Q然后关闭,之后q个PO你也不会再用CQ那么就不需要用update?/p>

因此Q我们来看看Q?

代码
  1. Foo foo=sess.load(Foo.class,id);    
  2. foo.setXXX(xxx);    
  3. sess.flush();   
  4. sess.commit();   

 

PO对象foo的操作都在一个Session生命周期内完成,因此不需要显式的q行sess.update(foo)q样的操作。Hibernate会自动监到foo对象已经被修改过Q因此就向数据库发送一个update的sql。当然如果你非要加上sess.update(foo)也不会错Q只不过q样做没有Q何必要?/p>

而跨Session的意思就是说q个PO对象在Session关闭之后Q你q把它当做一个VO来用Q后来你在Session外面又修改了它的属性,然后你又x开一个SessionQ把VO的属性修改保存到数据库里面,那么你就需要用update了?/p>

代码
  1. // in the first session    
  2. Cat cat = (Cat) firstSession.load(Cat.class, catId);    
  3. Cat potentialMate = new Cat();    
  4. firstSession.save(potentialMate);    
  5.   
  6. // in a higher tier of the application    
  7. cat.setMate(potentialMate);    
  8.   
  9. // later, in a new session    
  10. secondSession.update(cat);  // update cat    
  11. secondSession.update(mate); // update mate  

 

cat和mate对象是在W一个session中取得的Q在W一个session关闭之后Q他们就成了PO的第三种状态,和Session已经detached的POQ此时他们的状态信息仍然被保留下来了。当他们q入W二个session之后Q立d可以q行状态的更新。但是由于对cat的修Ҏ作:cat.setMate(potentialMate); 是在Session外面q行的,Hibernate不可能知道cat对象已经被改q了Q第二个Sessionq不知道q种修改Q因此一定要昑ּ的调用secondSession.update(cat); 通知HibernateQcat对象已经修改了,你必d送update的sql了?/p>

所以update的作用就在于此,它只会被用于当一个PO对象跨Sessionq行状态同步的时候才需要写。而一个PO对象当它不需要跨Sessionq行状态管理的时候,是不需要写update的?/p>

再谈谈saveOrUpdate的用场:

saveOrUpdate和update的区别就在于在跨Session的PO状态管理中QHibernate对PO采取何种{略?/p>

例如当你写一个DAOImpl的时候,让cat对象增加一个mateQ如下定义:

代码
  1. public void addMate(Cat cat, Mate mate) {   
  2.     Session session = ...;   
  3.     Transacton tx = ...;   
  4.     session.update(cat);   
  5.     cat.addMate(mate);   
  6.     tx.commit();   
  7.     session.close();   
  8. };  

 

昄你是需要把Hibernate的操作封装在DAO里面的,让业务层的程序员和Web层的E序员不需要了解HibernateQ直接对DAOq行调用?/p>

此时问题来了:上面的代码运行正有一个必要的前提Q那是Ҏ调用参数cat对象必须是一个已l被持久化过的POQ也是来说Q它应该首先从数据库查询出来Q然后才能这L。但是业务层的程序员昄不知道这U内部的玄妙Q如果他的业务是现在增加一个catQ然后再增加它的mateQ他昄会这栯用,new一个cat对象出来Q然后就addMateQ?/p>

代码
  1. Cat cat = new Cat();   
  2. cat.setXXX();   
  3. daoimpl.addMate(cat,mate);  

 

但是h意看Q这个cat对象只是一个VOQ它没有被持久化q,它还不是POQ它没有资格调用addMateҎQ因此调用addMateҎ不会真正往数据库里面发送update的sqlQ这个cat对象必须先被save到数据库Q在真正成ؓ一个PO之后Q才具备addMate的资根{?/p>

你必这h操作Q?/p>

代码
  1. Cat cat = new Cat();   
  2. cat.setXXX();   
  3. daoimpl.addCat(cat);   
  4. daoimpl.addMate(cat, mate);  

 

先持久化catQ然后才能对catq行其他的持久化操作。因此要求业务层的程序员必须清楚cat对象处于何种状态,到底是第一U,q是W三U。如果是W一U,p先saveQ再addMateQ如果是W三U,q接addMate?/p>

但是最致命的是Q如果整个Y件分层很多,业务层的E序员他拿到q个cat对象也可能是上层Web应用层传递过来的catQ他自己也不知道q个catI竟是VOQ没有被持久化过Q还是已l被持久化过Q那么他Ҏ没有办法写E序了?/p>

所以这LDAOImpl昄是有问题的,它会对业务层的程序员造成很多~程上的陷阱Q业务层的程序员必须深刻的了解他调用的每个DAO对PO对象q行了何U状态管理,必须深刻的了解他的PO对象在Q何时候处于什么确切的状态,才能保证~程的正性,昄q是做不到的Q但是有了saveOrUpdateQ这些问题就q刃而解了?/p>

现在你需要修改addMateҎQ?/p>

代码
  1. public void addMate(Cat cat, Mate mate) {   
  2.     Session session = ...;   
  3.     Transacton tx = ...;   
  4.     session.saveOrUpdate(cat);   
  5.     cat.addMate(mate);   
  6.     tx.commit();   
  7.     session.close();   
  8. };  

 

如上Q如果业务层的程序员传进来的是一个已l持久化q的PO对象Q那么Hibernate会更新cat对象(假设业务层的E序员在Session外面修改qcat的属?Q如果传q来的是一个新new出来的对象,那么向数据库saveq个PO对象?/p>

BTW: Hibernate此时I竟采取更新cat对象Q还是save cat对象Q取决于unsave-value的设定?/p>

q样Q业务层的程序员׃必再操心PO的状态问题了Q对于他们来_不管cat是new出来的对象,只是一个VO也好Q还是从数据库查询出来的的PO对象也好Q全部都是直接addMateOK了:

代码
  1. daoimple.addMate(cat, mate);  

 

q便是saveOrUpdate的作用?br />
Robbin老大的精?. http://www.javaeye.com/topic/2712?page=1



hilor 2007-12-06 16:49 发表评论
]]>
վ֩ģ壺 | | | | | | Ӫɽ| | | | ɳ| ָɽ| ƽ| | Ͼ| | | ͨ| | | ɽ| ɽ| | | Ʊ| | ˳| | | | | | | ½| Ȫ| | | ˼| | | ʼ|