当前位置: 代码迷 >> 综合 >> Druid 连接池配置文件(线程警告问题)
  详细解决方案

Druid 连接池配置文件(线程警告问题)

热度:39   发布时间:2023-11-26 17:25:30.0
  • 程序运行时的警告信息:

The web application [MiMarket] appears to have started a thread named [Druid-ConnectionPool-Destroy-485542448] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:java.lang.Thread.sleep(Native Method)

  • 我的配置文件:
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/db_shopping
username=root
password=#<!--initialSize: 初始化连接-->
initialSize=10
#<!--maxIdle: 最大空闲连接,已过时-->
#maxIdle = 10
#<!--minIdle: 最小空闲连接-->
minIdle=5
#<!--maxActive: 最大连接数量-->
maxActive=50
#<!--maxWait: 超时等待时间,以毫秒为单位-->
maxWait=50000
  • 关闭服务器时的警告:

The web application [MiMarket] registered the JDBC driver [com.alibaba.druid.proxy.DruidDriver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.

The web application [MiMarket] appears to have started a thread named [Abandoned connection cleanup thread] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:java.lang.Object.wait(Native Method)

因为我的程序是:写法糟糕的没有关闭连接,解除注册等操作的程序。。。

 

  • 配置文件的完善写法:
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/db_shopping
username=root
password=#<!--initialSize: 初始化连接-->
initialSize=10
#<!--maxIdle: 最大空闲连接,已过时-->
#maxIdle = 10
#<!--minIdle: 最小空闲连接-->
minIdle=5
#<!--maxActive: 最大连接数量-->
maxActive=50
#<!--removeAbandoned: 是否自动回收超时连接-->
removeAbandoned=true
#<!--removeAbandonedTimeout: 超时时间(以秒数为单位)-->
removeAbandonedTimeout=180
#<!--maxWait: 超时等待时间,以毫秒为单位-->
maxWait=50000validationQuery=SELECT 1
testOnBorrow=true
  • removeAbandonedTimeout  300 :

泄露的连接可以被删除的超时值,单位秒

  • removeAbandoned  false :

标记是否删除泄露的连接,如果他们超过了 removeAbandonedTimout 的限制的话。

设置为true,连接被认为是被泄露并且可以被删除,如果空闲时间超过 removeAbandonedTimeout 的话。

设置为true可以为写法糟糕的没有关闭连接的程序修复数据库连接。

如果开启"removeAbandoned",那么连接在被认为泄露时可能被池回收。

这个机制在(getNumIdle() < 2) and (getNumActive() > getMaxActive() - 3)时被触发。

  • 例:

maxActive=10, 活动连接为 8 或者空闲连接为 1 时可以触发"removeAbandoned",但这是基于活动连接没有被使用的时间超过"removeAbandonedTimeout"时,默认300秒。(在resultset中游历不被计算为被使用)

 

  • validationQuery  :

SQL查询,用来验证从连接池取出的连接,在将连接返回给调用者之前。如果指定,则查询必须是一个SQL SELECT并且必须返回至少一行记录

  • testOnBorrow  true  :

指明是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个。

注意:设置为true后如果要生效,validationQuery参数必须设置为非空字符串

  • 例:

假如连接池中的连接被数据库关闭了,应用通过连接池getConnection时,都可能获取到这些不可用的连接,且这些连接如果不被其他线程回收的话,它们不会被连接池被废除,也不会重新被创建。

这些连接占用了连接池的名额,项目本身作为服务端,数据库链接被关闭,客户端调用服务端就会出现大量的 timeout,客户端设置了超时时间,然后主动断开,服务端必然出现 close_wait ,由于 tomcat 默认最大线程数是 200,很快就挂掉。加大tomcat 默认线程(server.tomcat.max-threads=3000)也只是短时间内其他数据源链接不会死掉。

 

以上的配置文件写法适合小项目,解决了线程的问题,我的项目运行时没有再报线程警告,但是在服务器关闭时,Abandoned 线程(连接清理线程)未关闭,以及未解除注册的警告仍旧存在,必须在程序中添加如下监听。

  • AppListener:
import com.alibaba.druid.pool.DruidDataSource;
import com.mysql.jdbc.AbandonedConnectionCleanupThread;
import utils.DruidUtils;import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;@WebListener()
public class AppListener implements ServletContextListener {// Public constructor is required by servlet specpublic AppListener() {}@Overridepublic void contextInitialized(ServletContextEvent servletContextEvent) {}@Overridepublic void contextDestroyed(ServletContextEvent servletContextEvent) {DruidDataSource druidDataSource= (DruidDataSource) DruidUtils.getDataSource();druidDataSource.close();System.out.println("关闭连接池");try {Enumeration<Driver> drivers = DriverManager.getDrivers();while(drivers.hasMoreElements()){DriverManager.deregisterDriver(drivers.nextElement());System.out.println("解除注册");}} catch (SQLException e) {e.printStackTrace();}try {AbandonedConnectionCleanupThread.shutdown();System.out.println("关闭 Abandoned 线程");} catch (Exception e) {System.out.println("ContextFinalizer:SEVERE problem cleaning up: " + e.getMessage());e.printStackTrace();}}
}

注意:com.mysql.jdbc.AbandonedConnectionCleanupThread;

这个类文件在低一些版本的 MySQL 连接的 jar 包里没有。(MySQL 5.0.8 中就没有)

                                                                                                                                                                                        

  相关解决方案