2012-01-17 17 views
2

我想在獨立的web應用程序(自包含 - 不依賴於server.xml)實現jdbc池,以便它可以被移動到可能早於7.0的tomcat安裝。獨立的jdbc池實施內存泄漏

我連接到MSSQL Server和SourceForge的驅動程序(net.sourceforge.jtds.jdbc.Driver)

,一切都會運行,除了這個錯誤罰款:

SEVERE: The web application [/jdbc-pool] appears to have started a thread named [[Pool-Cleaner]:Tomcat Connection Pool[1-12524859]] but has failed to stop it. This is very likely to create a memory leak.

基於this我確定我需要關閉jdbc-pool數據源。我有這個最後一行的麻煩從該職位,但:​​

>> If it is configured in the application context, then this simply means you forgot to call DataSource.close on the connection pool when your web application is stopped.

> This is confusing advice because javax.sql.DataSource doesn't have a close() method.

In order to call close, one has to cast it to what ever the data source you are using.

如何才能知道我使用什麼類型的數據源,並在那裏是它的類?我能以某種方式從驅動程序jar中提取它嗎?

除了使用池的servlet外,我還使用了一個ServletContextListener,以便我可以從contextInitialized方法立即開始使用池連接。我開始添加代碼,以殺死這個了ServletContextListener的contextDestroyed方法連接,但得到了掛了其中的問號是:

import java.sql.Driver; 
import java.sql.DriverManager; 
import java.sql.SQLException; 
import java.util.Enumeration; 

import javax.naming.Context; 
import javax.naming.InitialContext; 
import javax.naming.NamingException; 
import javax.servlet.ServletContext; 
import javax.servlet.ServletContextEvent; 
import javax.servlet.ServletContextListener; 
import javax.sql.DataSource; 

public class JdbcPoolListener implements ServletContextListener { 

    @Override 
    public void contextInitialized(ServletContextEvent myServletContextEvent) { 

     // initialize jdbc-pool datasource to start out with pooled connections 
     try { 
      Context myContext = (Context) new InitialContext().lookup("java:comp/env"); 
      DataSource myDataSource = (DataSource) myContext.lookup("jdbc/db"); 
      myServletContextEvent.getServletContext().setAttribute("JdbcPool", myDataSource); 
     } catch (NamingException e) { 
      System.out.println("Error initializing jdbc-pool datasource"); 
      e.printStackTrace(); 
     } 
    } 

    @Override 
    public void contextDestroyed(ServletContextEvent myServletContextEvent) { 

     // failed attempt to close the data source 
     ServletContext myServletContext = myServletContextEvent.getServletContext(); 
     //DataSource myDataSource = (DataSource) myServletContext.getAttribute("JdbcPool"); 
     DataSource dataSource = (DataSource)((???) myServletContext.getAttribute(contextAttribute)).getConfiguration().getEnvironment().getDataSource(); 
     dataSource.close(); 
     myServletContext.removeAttribute("JdbcPool"); 

     // deregister JDBC driver to prevent Tomcat 7 from complaining about memory leaks 
     Enumeration<Driver> drivers = DriverManager.getDrivers(); 
     while (drivers.hasMoreElements()) { 
      Driver driver = drivers.nextElement(); 
      try { 
       DriverManager.deregisterDriver(driver); 
       System.out.println(String.format("Deregistering jdbc driver: %s", driver)); 
      } catch (SQLException e) { 
       System.out.println(String.format("Error deregistering driver %s", driver)); 
       e.printStackTrace(); 
      } 
     } 
    } 
} 
+0

它是最有可能net.sourceforge.jtds.jdbcx.JtdsDataSource並嘗試了socketTimeout設置是否空轉,這將關閉連接播放。更多的在司機的文檔中。 – 2012-01-18 01:22:57

回答

2

解決這個問題,我注意到tomcat.jdbc.pool.DataSourceProxy有密切的方法,所以我投了datasource作爲DataSourceProxy,然後調用它關閉。現在,我不再在日誌中獲取tomcat內存泄漏錯誤。

SOLUTION:

import java.sql.Driver; 
import java.sql.DriverManager; 
import java.sql.SQLException; 
import java.util.Enumeration; 

import javax.naming.Context; 
import javax.naming.InitialContext; 
import javax.naming.NamingException; 
import javax.servlet.ServletContext; 
import javax.servlet.ServletContextEvent; 
import javax.servlet.ServletContextListener; 
import javax.sql.DataSource; 

import org.apache.tomcat.jdbc.pool.DataSourceProxy; 

public class JdbcPoolListener implements ServletContextListener { 

    @Override 
    public void contextInitialized(ServletContextEvent myServletContextEvent) { 

     // initialize jdbc-pool datasource to start out with pooled connections 
     try { 
      Context myContext = (Context) new InitialContext().lookup("java:comp/env"); 
      DataSource myDataSource = (DataSource) myContext.lookup("jdbc/cf"); 
      myServletContextEvent.getServletContext().setAttribute("JdbcPool", myDataSource); 
     } catch (NamingException e) { 
      System.out.println("Error initializing jdbc-pool datasource"); 
      e.printStackTrace(); 
     } 
    } 

    @Override 
    public void contextDestroyed(ServletContextEvent myServletContextEvent) { 

    // close datasource from proxy? 
    ServletContext myServletContext = myServletContextEvent.getServletContext(); 
     DataSourceProxy myDataSource = (DataSourceProxy) myServletContext.getAttribute("JdbcPool"); 
     myDataSource.close();  
     myServletContext.removeAttribute("JdbcPool"); 

     // deregister JDBC driver to prevent Tomcat 7 from complaining about memory leaks 
     Enumeration<Driver> drivers = DriverManager.getDrivers(); 
     while (drivers.hasMoreElements()) { 
      Driver driver = drivers.nextElement(); 
      try { 
       DriverManager.deregisterDriver(driver); 
       System.out.println(String.format("Deregistering jdbc driver: %s", driver)); 
      } catch (SQLException e) { 
       System.out.println(String.format("Error deregistering driver %s", driver)); 
       e.printStackTrace(); 
      } 
     } 
    } 
} 
你的具體情況
+2

我想如果你使用org.apache.tomcat.jdbc.pool.DataSource類,你會得到相同的結果,因爲它擴展了DataSourceProxy,並且DataSourceProxy實現了PoolConfiguration,而DataSourceProxy具有close()方法來關閉池。 – 2012-01-18 01:32:56

+0

@Sergey Benner謝謝澄清 – Geronimo 2012-01-18 02:05:33