-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 
Author Message
 Post subject: Connection Leak
PostPosted: Fri Aug 12, 2005 5:05 am 
Newbie

Joined: Mon Aug 08, 2005 4:16 pm
Posts: 15
Hi,

I am using Hibernate 3.0 with Spring and Weblogic. I use a connection provider that will internally lookup a datasource either using JNDI or DBCP based on whether I am running the application in container or out of container. I use the a servlet filter in in container to bind the session factory against the thread local. However, closing the session in the servlet filter doesn't call the connection provider to close the connection and hance causes connection leak. Any help would be highly appreciated.

Code for the connection provider:
---------------------------------------

Code:
public abstract class DataSourceConnectionProvider implements
      ConnectionProvider {

   // Logger
   private static Log log = LogFactory
         .getLog(DataSourceConnectionProvider.class);

   // Datasource
   private String dsBeanName;

   /**
    * Initializes the datasource.
    */
   public DataSourceConnectionProvider() {
      dsBeanName = getDataSourceName();
   }

   /**
    * Does nothing.
    *
    * @param arg
    * @throws HibernateException
    * @see org.hibernate.connection.ConnectionProvider#configure(java.util.Properties)
    */
   public void configure(Properties arg) throws HibernateException {
   }

   /**
    * Gets the connection.
    *
    * @return Connection
    * @throws SQLException
    * @see org.hibernate.connection.ConnectionProvider#getConnection()           
    */
   public Connection getConnection() throws SQLException {
      try {
          DataSource ds = (DataSource) ComponentFactory.getBean(dsBeanName);
         return ds.getConnection();
      } finally {
         if (log.isInfoEnabled()) {
            log.info("Connection retrieved");
         }
      }
   }

   /**
    * Closes the connection.
    *
    * @param con
    * @throws SQLException
    * @see org.hibernate.connection.ConnectionProvider#closeConnection(java.sql.Connection)
    */
   public void closeConnection(Connection con) throws SQLException {
      con.close();
      if (log.isInfoEnabled()) {
         log.info("Connection closed");
      }
   }

   /**
    * Do nothing.
    * @throws HibernateException.
    * @see DataSourceConnectionProvider.close
    */
   public void close() throws HibernateException {
   }

   /**
    * Should be overridden by the sub-classes.
    *
    * @return Datasource bean name.
    */
   protected abstract String getDataSourceName();

}


Code for the creating session factory
------------------------------------------

Code:
public class HibernateConfiguration {

   // Logger
   private static final Log LOG = LogFactory
         .getLog(HibernateConfiguration.class);

   // Session factory
   private SessionFactory sessionFactory;

   /**
    * Initializes the session factory.
    *
    * @param mappings MappingLocations.
    * @param props Configuration to use.
    * @param conProviderClass Hibernate connection provider class.
    */
   public HibernateConfiguration(Class[] mappings, Properties props,
         Class conProviderClass) {
      if (!ConnectionProvider.class.isAssignableFrom(conProviderClass)) {
         throw new IllegalArgumentException("Invalid connection provider");
      }
      Configuration config = new Configuration();
      config.setProperties(props);
      config.setProperty(Environment.CONNECTION_PROVIDER, conProviderClass
            .getName());
      for (int i = 0; i < mappings.length; i++) {
         config.addClass(mappings[i]);
      }
      sessionFactory = config.buildSessionFactory();
   }

   /**
    * Gets a new session.
    *
    * @return Returns a new session.
    */
   public Session getSession() {
      return sessionFactory.openSession();
   }

}


Code for accessing the session
------------------------------------

Code:
public class HibernateUtil {
   
   // Bean name under which hibernate configuration is available
   public static final String CONFIG_SUFFIX = "hibernateConfig";
   
   // Logger
   private static final Log LOG = LogFactory.getLog(HibernateUtil.class);
   
    // Map of domain names to utility instanes
    private static final Map UTIL_MAP = new HashMap();

   // Session factory that is used
   private HibernateConfiguration config = null;

   // Thread-local sessions
   private final ThreadLocal sessions = new ThreadLocal();

    // Thread-local sessions
    private final ThreadLocal transactions = new ThreadLocal();
   
    // Domain name
    private String domainName;
   
    /**
     * Creates the utility singleton for the domain
     * @param domainName
     */
    private HibernateUtil(String domainName) {
        this.domainName = domainName;
        String beanName = domainName + "." + CONFIG_SUFFIX;
        config = (HibernateConfiguration)ComponentFactory.getBean(beanName);
    }
   
    /**
     * Returns the singleton hibernate utility for the given domain.
     *
     * @param domainName Domain name.
     * @return Hibernate utility.
     */
    public static final HibernateUtil getInstance(String domainName) {
       
        HibernateUtil util = null;
        synchronized(HibernateUtil.class) {
           util = (HibernateUtil)UTIL_MAP.get(domainName);
            if(util == null) {
               util = new HibernateUtil(domainName);
                UTIL_MAP.put(domainName, util);
            }
        }
        return util;
       
    }

   /**
    * Gets the current session.
    *
    * If there is no current session a new session is created. This method
    * is thread safe as the session is bound to the threadocal.
    *
    * @return Current session.
    */
   public Session currentSession() {
      Session session = (Session) sessions.get();
      if(session == null) {
         return getSession();
      }else if(!session.isOpen()) {
         // Session has already been closed - clean up
         sessions.set(null);
         return getSession();
      }
      return session;
   }

   /**
    * Flushes and closes the current session.
    *
    * The current session is also unbound from the thread-local. This
    * method is not required in a managed environment as from Hibernate 3 this
    * is automatically done as part of transaction synchronization.
    *
    * @return Current session.
    */
   public void closeSession() {
      Session session = (Session) sessions.get();
        if (session != null) {
            try {
                // TODO We should not be doing this.
                session.connection().close();
            }catch(SQLException ex) {
                LOG.fatal(ex.getMessage(), ex);
            }
            session.close();
            if(LOG.isInfoEnabled()) {
               LOG.info("Connection closed for domain " + domainName);
            }
        }
      sessions.set(null);
        transactions.set(null);
   }
   
    /**
     * Begins the transaction.
     *
     * @return Begins the transaction.
     */
    public void beginTransaction() {
       transactions.set(currentSession().beginTransaction());
    }
   
    /**
     * Commits the transaction.
     *
     * @return Commits the transaction.
     */
    public void commitTransaction() {
        Transaction tx = (Transaction)transactions.get();
        if(tx != null) {
            getSession().flush();
           tx.commit();
           transactions.set(null);
        }
    }
   
    /**
     * Rolls back the transaction.
     *
     * @return Rolls back the transaction.
     */
    public void rollbackTransaction() {
        Transaction tx = (Transaction)transactions.get();
        if(tx != null) {
            getSession().flush();
           tx.rollback();
           transactions.set(null);
        }
    }
   
    /**
     * Flushes the current session.
     *
     */
    public void flush() {
       Session session = getSession();
        if(session != null) {
           session.flush();
        }
    }
   
   /*
    * Gets a new session.
    */
   private Session getSession() {
      Session session = config.getSession();
      sessions.set(session);
      return session;
   }

}


Code for closing the session
---------------------------------

Code:
public class HibernateSessionFilter extends AbstractHttpFilter {
   
   // Logger
   private static final Log LOG = LogFactory.getLog(HibernateSessionFilter.class);
   
    // Init parameter specifying the domains served by this filter
    private static final String DOMAIN_NAMES = "domain.names";
   
    // Domain names
    private String[] domainNames;
   
    /**
     * Initializes the hibernate domain names.
     */
    public void init(FilterConfig config) throws ServletException {
        String dns = config.getInitParameter(DOMAIN_NAMES);
        if(LOG.isInfoEnabled()) {
            LOG.info("Hibernate configurations: " + dns);
        }
        StringTokenizer tok = new StringTokenizer(dns, ",");
        domainNames = new String[tok.countTokens()];
        for(int i = 0;i < domainNames.length;i++) {
           domainNames[i] = tok.nextToken();
            if(LOG.isInfoEnabled()) {
                LOG.info("Hibernate configuration: " + domainNames[i]);
            }
        }
        if(LOG.isInfoEnabled()) {
            LOG.info("Number of hibernate utilities initialized: " + domainNames.length);
        }
    }

   /**
    * Filters the request to make sure hibernate sessions are closed.
    *
    * @param request In coming request.
    * @param response Out going response.
    * @param chain Filter chain.
    *
    */
   public void doFilter(HttpServletRequest request,
         HttpServletResponse response, FilterChain chain)
         throws IOException, ServletException {
        openSessions(request);
      try {
         chain.doFilter(request, response);
      }finally {
            closeSessions(request);
      }

   }

   /**
    * @param request
    */
   private void closeSessions(HttpServletRequest request) {
      for(int i = 0;i < domainNames.length;i++) {
         HibernateUtil.getInstance(domainNames[i]).closeSession();
          if(LOG.isInfoEnabled()) {
              LOG.info("Session " + domainNames[i] +
                      " closed for request: " + request.getRequestURI());
          }
      }
   }

   /**
    * @param request
    */
   private void openSessions(HttpServletRequest request) {
      for(int i = 0;i < domainNames.length;i++) {
            HibernateUtil.getInstance(domainNames[i]).currentSession();
            if(LOG.isInfoEnabled()) {
                LOG.info("Session " + domainNames[i] +
                        " opened for request: " + request.getRequestURI());
            }
        }
   }

}


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 12, 2005 5:26 am 
Expert
Expert

Joined: Thu Sep 04, 2003 8:23 am
Posts: 368
I've heard of some problems where the filter does not work in the same thread as the servlet under tomcat thus causing trouble with the ThreadLocal pattern. Are you sure the close method is call on the session ?

_________________
Seb
(Please don't forget to give credits if you found this answer useful :)


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 12, 2005 9:32 am 
Newbie

Joined: Mon Aug 08, 2005 4:16 pm
Posts: 15
I have changed the configuration to use the JNDI name of the datasource directly and set aggressive connection closure straergy to close connection after every statement. This hasn't made any difference, in fact it has made it worse and the connection leak is happening lot sooner.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 12, 2005 12:04 pm 
Newbie

Joined: Mon Aug 08, 2005 4:16 pm
Posts: 15
After further investigation, I can see the session being closed. However, that doesn't call the close(Connection connection) method on the connection provider. Here are my hibernate properties. Any help would be highly appreciated,

Code:
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
            <prop key="hibernate.jdbc.batch_size">100</prop>
            <prop key="hibernate.show_sql">false</prop>
            <prop key="hibernate.auto_import">true</prop>
            <prop key="hibernate.cglib.use_reflection_optimizer">false</prop>
            <prop key="hibernate.query.substitutions">true=1,false=0</prop>
            <prop key="hibernate.use_outer_join">true</prop>
            <prop key="hibernate.max_fetch_depth">10</prop>
            <prop key="hibernate.query.factory_class">org.hibernate.hql.classic.ClassicQueryTranslatorFactory</prop>
            <prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</prop>


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.