<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Sealyu

    --- 博客已遷移至: http://www.sealyu.com/blog

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      618 隨筆 :: 87 文章 :: 225 評論 :: 0 Trackbacks

    Spring+Hibernate做項目, 發現有member在不加事務的情況下就去調用 getSession() 方法, 結果導致數據庫連接不能釋放, 也無法正常的提交事務(只能做查詢, 不能做save(), update()). 如果配合連接池使用的話, 不出幾分鐘就會導致連接池無法拿到新連接的情況.

    不過, 只要給DAO或者Service加入了事務, 就不會出現連接泄漏的問題.

    談談解決方案:

    最佳方案: 加入事務, 例如 tx 標簽或者 @Transactional 都可以.

    最笨方案: 修改代碼, 使用 HibernateTemplate 來完成相關操作:

           public List queryAll( final String hql, final Object... args) {

                  List list = getHibernateTemplate().executeFind( new HibernateCallback() {

                           public Object doInHibernate(Session session)

                           throws HibernateException, SQLException {

                          Query query = session.createQuery(hql);

                          

                           for ( int i =0; i < args. length ; i++) {

                                 query.setParameter(i, args[i]);

                          }

                          

     

                          List list = query.list();

                           return list;

                          }

                         });

                               

                  return list;        

           }

           public Serializable save(Object entity) {

                  return getHibernateTemplate().save(entity);

           }

     

    HibernateDaoSupport 代碼里面的原始說明文檔指出直接調用getSession()方法必須用配套的releaseSession(Session session)來釋放連接, 根據我的測試, 就算配置了 OpenSessionInViewFilter(前提: 不加事務), 也不會關閉這個Session. 也許有人說可以用連接池, 這種情況和Db pool沒關系, 用了pool就會發現連接很快就會滿, 只會over的更快.  反過來, 如果不配置OpenSessionInViewFilter, 在DAO里提前用 releaseSession()關閉連接, 就可能會在JSP中出現Lazy載入異常. 另一個不配事務的問題就是無法更新或者插入數據. 下面就是原始的JavaDoc中的說明:

           /**

             * Obtain a Hibernate Session, either from the current transaction or

             * a new one. The latter is only allowed if the

             * {@link org.springframework.orm.hibernate3.HibernateTemplate#setAllowCreate "allowCreate"}

             * setting of this bean's {@link #setHibernateTemplate HibernateTemplate} is "true".

             * <p><b> Note that this is not meant to be invoked from HibernateTemplate code

             * but rather just in plain Hibernate code. </b> Either rely on a thread - bound

             * Session or use it in combination with {@link #releaseSession} .

             * <p> In general, it is recommended to use HibernateTemplate, either with

             * the provided convenience operations or with a custom HibernateCallback

             * that provides you with a Session to work on. HibernateTemplate will care

             * for all resource management and for proper exception conversion.

             * @return the Hibernate Session

             * @throws DataAccessResourceFailureException if the Session couldn't be created

             * @throws IllegalStateException if no thread - bound Session found and allowCreate=false

             * @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession(SessionFactory, boolean)

             */

           protected final Session getSession()

               throws DataAccessResourceFailureException, IllegalStateException {

     

                  return getSession( this . hibernateTemplate .isAllowCreate());

           }

     

           /**

             * Close the given Hibernate Session, created via this DAO's SessionFactory,

             * if it isn't bound to the thread (i.e. isn't a transactional Session).

             * <p> Typically used in plain Hibernate code, in combination with

             * {@link #getSession} and {@link #convertHibernateAccessException} .

             * @param session the Session to close

             * @see org.springframework.orm.hibernate3.SessionFactoryUtils#releaseSession

             */

           protected final void releaseSession(Session session) {

                  SessionFactoryUtils.releaseSession(session, getSessionFactory());

           }

     

     

     HibernateDaoSupport用ThreadLocal保存Session列表并編寫一個配套的過濾器來顯式關閉Session, 并在關閉之前嘗試提交事務. 下面是重寫的 HibernateDaoSupport 代碼:

     

    						package org.springframework.orm.hibernate3.support;

    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.List;

    import org.hibernate.HibernateException;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;

    import org.springframework.dao.DataAccessException;
    import org.springframework.dao.DataAccessResourceFailureException;
    import org.springframework.dao.support.DaoSupport;
    import org.springframework.orm.hibernate3.HibernateTemplate;
    import org.springframework.orm.hibernate3.SessionFactoryUtils;


    /**
    * 修改后的避免連接泄漏的 HibernateDaoSupport, 多連接版本, 不保證跨DAO的事務.
    *
    * @author 劉長炯
    * Date: 2009-3-11
    */
    publicabstractclass HibernateDaoSupport extends DaoSupport {
    /** 使用 ThreadLocal 保存打開的 Session 列表 */
    privatestaticfinal ThreadLocal< List<Session> > sessions = new ThreadLocal< List<Session> >();

    /**
    * 獲取Hibernate連接.
    * @return
    */
    publicstatic List<Session> getSessionList() {
    //1. 先看看是否有了List get()
    List list = sessions.get();
    // 2. 沒有的話從創建一個, put()
    if(list == null) {
    list = new ArrayList();
    sessions.set(list);
    }
    // 3. 返回 Session
    return list;
    }

    /**
    * 關閉當前線程中未正常釋放的 Session.
    */
    publicstaticvoid closeSessionList() {
    // 1. 先看看是否有了List get()
    List<Session> list = sessions.get();
    // 2. 有的話就直接關閉
    if(list != null) {
    System.out.println(SimpleDateFormat.getDateTimeInstance().format(new java.util.Date()) +
    " -------- 即將釋放未正常關閉的 Session");


    for(Session session : list) {
    System.out.println("正在關閉 session =" + session.hashCode());
    // ! 關閉前事務提交
    if(session.isOpen()) {
    try {
    session.getTransaction().commit();
    } catch(Exception ex) {
    try {
    session.getTransaction().rollback();
    } catch (HibernateException e) {
    // TODO Auto-generated catch block
    //e.printStackTrace();
    }
    }
    try {
    session.close();
    } catch(Exception ex) {

    }

    }
    //releaseSession(session); // 無法調用
    }
    sessions.remove();
    }

    }

    private HibernateTemplate hibernateTemplate;


    /**
    * Set the Hibernate SessionFactory to be used by this DAO.
    * Will automatically create a HibernateTemplate for the given SessionFactory.
    * @see #createHibernateTemplate
    * @see #setHibernateTemplate
    */
    publicfinalvoid setSessionFactory(SessionFactory sessionFactory) {
    if (this.hibernateTemplate == null || sessionFactory != this.hibernateTemplate.getSessionFactory()) {
    this.hibernateTemplate = createHibernateTemplate(sessionFactory);
    }
    }

    /**
    * Create a HibernateTemplate for the given SessionFactory.
    * Only invoked if populating the DAO with a SessionFactory reference!
    * <p>Can be overridden in subclasses to provide a HibernateTemplate instance
    * with different configuration, or a custom HibernateTemplate subclass.
    * @param sessionFactory the Hibernate SessionFactory to create a HibernateTemplate for
    * @return the new HibernateTemplate instance
    * @see #setSessionFactory
    */
    protected HibernateTemplate createHibernateTemplate(SessionFactory sessionFactory) {
    returnnew HibernateTemplate(sessionFactory);
    }

    /**
    * Return the Hibernate SessionFactory used by this DAO.
    */
    publicfinal SessionFactory getSessionFactory() {
    return (this.hibernateTemplate != null ? this.hibernateTemplate.getSessionFactory() : null);
    }

    /**
    * Set the HibernateTemplate for this DAO explicitly,
    * as an alternative to specifying a SessionFactory.
    * @see #setSessionFactory
    */
    publicfinalvoid setHibernateTemplate(HibernateTemplate hibernateTemplate) {
    this.hibernateTemplate = hibernateTemplate;
    }

    /**
    * Return the HibernateTemplate for this DAO,
    * pre-initialized with the SessionFactory or set explicitly.
    * <p><b>Note: The returned HibernateTemplate is a shared instance.</b>
    * You may introspect its configuration, but not modify the configuration
    * (other than from within an {@link #initDao} implementation).
    * Consider creating a custom HibernateTemplate instance via
    * <code>new HibernateTemplate(getSessionFactory())</code>, in which
    * case you're allowed to customize the settings on the resulting instance.
    */
    publicfinal HibernateTemplate getHibernateTemplate() {
    returnthis.hibernateTemplate;
    }

    protectedfinalvoid checkDaoConfig() {
    if (this.hibernateTemplate == null) {
    thrownew IllegalArgumentException("'sessionFactory' or 'hibernateTemplate' is required");
    }
    }


    /**
    * Obtain a Hibernate Session, either from the current transaction or
    * a new one. The latter is only allowed if the
    * {@link org.springframework.orm.hibernate3.HibernateTemplate#setAllowCreate "allowCreate"}
    * setting of this bean's {@link #setHibernateTemplate HibernateTemplate} is "true".
    * <p><b>Note that this is not meant to be invoked from HibernateTemplate code
    * but rather just in plain Hibernate code.</b> Either rely on a thread-bound
    * Session or use it in combination with {@link #releaseSession}.
    * <p>In general, it is recommended to use HibernateTemplate, either with
    * the provided convenience operations or with a custom HibernateCallback
    * that provides you with a Session to work on. HibernateTemplate will care
    * for all resource management and for proper exception conversion.
    * @return the Hibernate Session
    * @throws DataAccessResourceFailureException if the Session couldn't be created
    * @throws IllegalStateException if no thread-bound Session found and allowCreate=false
    * @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession(SessionFactory, boolean)
    */
    protectedfinal Session getSession()
    throws DataAccessResourceFailureException, IllegalStateException {
    Session session = getSession(this.hibernateTemplate.isAllowCreate());

    // 開始事務
    try {
    session.beginTransaction();
    } catch (HibernateException e) {
    e.printStackTrace();
    }

    getSessionList().add(session);

    return session;
    }

    /**
    * Obtain a Hibernate Session, either from the current transaction or
    * a new one. The latter is only allowed if "allowCreate" is true.
    * <p><b>Note that this is not meant to be invoked from HibernateTemplate code
    * but rather just in plain Hibernate code.</b> Either rely on a thread-bound
    * Session or use it in combination with {@link #releaseSession}.
    * <p>In general, it is recommended to use
    * {@link #getHibernateTemplate() HibernateTemplate}, either with
    * the provided convenience operations or with a custom
    * {@link org.springframework.orm.hibernate3.HibernateCallback} that
    * provides you with a Session to work on. HibernateTemplate will care
    * for all resource management and for proper exception conversion.
    * @param allowCreate if a non-transactional Session should be created when no
    * transactional Session can be found for the current thread
    * @return the Hibernate Session
    * @throws DataAccessResourceFailureException if the Session couldn't be created
    * @throws IllegalStateException if no thread-bound Session found and allowCreate=false
    * @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession(SessionFactory, boolean)
    */
    protectedfinal Session getSession(boolean allowCreate)
    throws DataAccessResourceFailureException, IllegalStateException {

    return (!allowCreate ?
    SessionFactoryUtils.getSession(getSessionFactory(), false) :
    SessionFactoryUtils.getSession(
    getSessionFactory(),
    this.hibernateTemplate.getEntityInterceptor(),
    this.hibernateTemplate.getJdbcExceptionTranslator()));
    }

    /**
    * Convert the given HibernateException to an appropriate exception from the
    * <code>org.springframework.dao</code> hierarchy. Will automatically detect
    * wrapped SQLExceptions and convert them accordingly.
    * <p>Delegates to the
    * {@link org.springframework.orm.hibernate3.HibernateTemplate#convertHibernateAccessException}
    * method of this DAO's HibernateTemplate.
    * <p>Typically used in plain Hibernate code, in combination with
    * {@link #getSession} and {@link #releaseSession}.
    * @param ex HibernateException that occured
    * @return the corresponding DataAccessException instance
    * @see org.springframework.orm.hibernate3.SessionFactoryUtils#convertHibernateAccessException
    */
    protectedfinal DataAccessException convertHibernateAccessException(HibernateException ex) {
    returnthis.hibernateTemplate.convertHibernateAccessException(ex);
    }

    /**
    * Close the given Hibernate Session, created via this DAO's SessionFactory,
    * if it isn't bound to the thread (i.e. isn't a transactional Session).
    * <p>Typically used in plain Hibernate code, in combination with
    * {@link #getSession} and {@link #convertHibernateAccessException}.
    * @param session the Session to close
    * @see org.springframework.orm.hibernate3.SessionFactoryUtils#releaseSession
    */
    protectedfinalvoid releaseSession(Session session) {
    SessionFactoryUtils.releaseSession(session, getSessionFactory());
    }

    }
    用這個類來覆蓋Spring內置的那個HibernateDaoSupport, 然后隨便編寫一個過濾器, 如下所示:
    						public
    void doFilter(ServletRequest req, ServletResponse res,
    FilterChain chain) throws IOException, ServletException {

    req.setCharacterEncoding(this.charset);
    chain.doFilter(req, res);
    // 關閉遺漏的 Session
    HibernateDaoSupport.closeSessionList();
    }


    把這個過濾器配置在過濾器鏈的第一個, 就OK了.

    最 后也許會有人說, 為什么不用tx標簽在Spring中來配置一個通配符就全部加入了事務了呢? 不過很遺憾, 經測試發現此方式無法實現跨DAO的Hibernate事務, 所以只好很無奈的放棄了這種方式. 這就是文章一開頭提到的最佳方案, 也許是成本最低的方案了, 但是我卻沒采用, 一是因為事務問題, 二是因為每個有問題的dao/service包都要修改一次XML配置文件, 我很懶惰, 不想去看那些代碼都在哪些包里面. Tx標簽的配置方式如下所示:

    						<?
    xml
    version
    ="1.0"
    encoding
    ="UTF-8"?>
    <beansxmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"
    >

    <beanid="sessionFactory"
    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <propertyname="configLocation"
    value="classpath:hibernate.cfg.xml">
    </property>
    </bean>

    <beanid="StudentDAO"class="dao.StudentDAO">
    <propertyname="sessionFactory">
    <refbean="sessionFactory"/>
    </property>
    </bean>

    <!-- 聲明一個 Hibernate 3 的 事務管理器供代理類自動管理事務用 -->
    <beanid="transactionManager"
    class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <propertyname="sessionFactory">
    <reflocal="sessionFactory"/>
    </property>
    </bean>

    <aop:config>
    <!-- 切入點指明了在執行dao.StudentDAO的所有方法時產生事務攔截操作 -->
    <aop:pointcutid="daoMethods"
    expression="execution(* dao.StudentDAO.*(..))"/>
    <!-- 定義了將采用何種攔截操作,這里引用到 txAdvice -->
    <aop:advisoradvice-ref="txAdvice"
    pointcut-ref="daoMethods"/>
    </aop:config>

    <!-- 這是事務通知操作,使用的事務管理器引用自 transactionManager -->
    <tx:adviceid="txAdvice"transaction-manager="transactionManager">
    <tx:attributes>
    <!-- 指定哪些方法需要加入事務,這里懶惰一下全部加入,可以使用通配符來只加入需要的方法 -->
    <tx:methodname="*"propagation="REQUIRED"/>
    </tx:attributes>
    </tx:advice>

    </beans>

    其它加事務的方式有老式的Spring1.2的, 還有Annotation的, 這些都是一個解決方案, 就是給DAO/Service加入事務. 如果您有更好的辦法, 歡迎來信探討.

    posted on 2010-02-22 16:43 seal 閱讀(2301) 評論(0)  編輯  收藏 所屬分類: SpringHibernate
    主站蜘蛛池模板: 国产亚洲午夜精品| 亚洲精品456人成在线| 男女超爽视频免费播放| 丁香花免费完整高清观看| 亚洲AV成人精品网站在线播放| 国产va免费观看| 亚洲国产精品尤物yw在线| 亚洲第一成年免费网站| 国产青草视频在线观看免费影院| 香蕉大伊亚洲人在线观看| 午夜宅男在线永久免费观看网| 亚洲国产精品综合久久2007| 大地资源在线观看免费高清| 亚洲欧美日本韩国| 国产一级大片免费看| 欧洲精品码一区二区三区免费看| 免费一级毛片在级播放| 又硬又粗又长又爽免费看 | 在线播放免费人成视频在线观看 | 亚洲AV日韩精品一区二区三区| 国产综合成人亚洲区| 亚洲日韩在线观看| 老司机69精品成免费视频| 亚洲狠狠综合久久| 我的小后妈韩剧在线看免费高清版| 亚洲一级毛片视频| 亚洲国产成人精品91久久久| 久久精品成人免费看| 激情综合亚洲色婷婷五月APP| 欧洲精品免费一区二区三区| 一区二区三区在线免费观看视频| 亚洲无码在线播放| 1a级毛片免费观看| 黄色a三级三级三级免费看| 亚洲精品国产精品乱码视色 | 亚洲精品视频观看| 日韩一区二区免费视频| 免费毛片在线看不用播放器| 精品亚洲成A人无码成A在线观看 | 人妻仑刮八A级毛片免费看| 亚洲av无码一区二区三区不卡 |