OpenSessionInViewFilter解決Web應(yīng)用程序的問題 轉(zhuǎn)自:Potain 的BLOG
OpenSessionInView
另外,你不愿意你的DAO測(cè)試代碼每次都打開關(guān)系Session,因此,我們一般會(huì)采用OpenSessionInView模式。
OpenSessionInViewFilter解決Web應(yīng)用程序的問題
如果程序是在正常的Web程序中運(yùn)行,那么Spring的OpenSessionInViewFilter能夠解決問題,它: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); } }
為什么綁定以后,就可以防止每次不會(huì)新開一個(gè)Session呢?看看HibernateDaoSupport的情況:
publicfinal void setSessionFactory(SessionFactory sessionFactory) { this.hibernateTemplate = new HibernateTemplate(sessionFactory); } protectedfinal HibernateTemplate getHibernateTemplate() { return hibernateTemplate; }
我們的DAO將使用這個(gè)template進(jìn)行操作:
publicabstract class BaseHibernateObjectDao extends HibernateDaoSupport implements BaseObjectDao {protected BaseEntityObject getByClassId(finallong id) { BaseEntityObject obj = (BaseEntityObject) getHibernateTemplate() .execute(new HibernateCallback() {
publicObject doInHibernate(Session session) throws HibernateException { return session.get(getPersistentClass(), newLong(id)); }
}); return obj; }
public void save(BaseEntityObject entity) { getHibernateTemplate().saveOrUpdate(entity); }
public void remove(BaseEntityObject entity) { try {
getHibernateTemplate().delete(entity); } catch (Exception e) { thrownew FlexEnterpriseDataAccessException(e); } }
public void refresh(final BaseEntityObject entity) { getHibernateTemplate().execute(new HibernateCallback() {
publicObject doInHibernate(Session session) throws HibernateException { session.refresh(entity); returnnull; }
}); }
public void replicate(finalObject entity) { getHibernateTemplate().execute(new HibernateCallback() {
publicObject doInHibernate(Session session) throws HibernateException { session.replicate(entity, ReplicationMode.OVERWRITE); returnnull; }
}); }
publicObject 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()); } }
publicstatic 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 thrownew CleanupFailureDataAccessException( "Cannot close Hibernate session", ex.getSQLException()); } catch (HibernateException ex) { thrownew CleanupFailureDataAccessException( "Cannot close Hibernate session", ex); } }
HibernateInterceptor和OpenSessionInViewInterceptor的問題
使用同樣的方法,這兩個(gè)Interceptor可以用來解決問題。但是關(guān)鍵的不同之處在于,它們的力度只能定義在DAO或業(yè)務(wù)方法上,而不是在我們的Test方法上,除非我們把它們應(yīng)用到TestCase的方法上,但你不大可能為TestCase去定義一個(gè)接口,然后把Interceptor應(yīng)用到這個(gè)接口的某些方法上。直接使用HibernateTransactionManager也是一樣的。因此,如果我們有這樣的測(cè)試:
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);
- 每次DAO執(zhí)行都會(huì)啟動(dòng)一個(gè)session和關(guān)閉一個(gè)session
- 如果我們定義了一個(gè)lazy的關(guān)系,那么最后的Category savedChild = (Category ) savedParent.getChildren().get(0);將會(huì)讓hibernate報(bào)錯(cuò)。
解決方案
一種方法是對(duì)TestCase應(yīng)用Interceptor或者TransactionManager,但這個(gè)恐怕會(huì)造成很多麻煩。除非是使用增強(qiáng)方式的AOP.我前期采用這種方法(Aspectwerkz),在Eclipse里面也跑得含好。
另一種方法是在TestCase的setup和teardown里面實(shí)現(xiàn)和Filter完全一樣的處理,其他的TestCase都從這個(gè)TestCase繼承,這種方法是我目前所使用的。
Jolestar補(bǔ)充:openSessionInView的配置方法:
?? <filter>
? ? ? ? <filter-name>opensession</filter-name>
? ? ? ? <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
? ? ? ? <init-param>
? ? ? ? ? ? <param-name>singleSession</param-name>
? ? ? ? ? ? <param-value>false</param-value>
? ? ? ? </init-param>
? ? </filter>
posted on 2006-09-26 11:01 康文 閱讀(553) 評(píng)論(0) 編輯 收藏 所屬分類: java