我正在尝试在独立的 Web 应用程序(自包含 - 不依赖于 server.xml)中实现 jdbc-pool,以便它可以移动到可能早于 7.0 的 tomcat 安装。
我正在使用 sourceforge 驱动程序 (net.sourceforge.jtds.jdbc.Driver) 连接到 MSSQL Server
除此错误外一切正常:
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();
}
}
}
}
最佳答案
解决了这个问题,我注意到 tomcat.jdbc.pool.DataSourceProxy
有一个 close 方法,所以我将数据源转换为 DataSourceProxy
,然后对其调用 closed .我现在不再在日志中收到 tomcat 内存泄漏错误。
解决方案:
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();
}
}
}
}
关于java - 独立的 jdbc-pool 实现内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8903379/