java tomcat maven war 项目
用 druid 连接 mysql 数据库
运行没毛病,就是报告内存泄漏
十一月 25, 2022 8:56:52 下午 org.apache.catalina.loader.WebappClassLoaderBase clearReferencesThreads 警告: Web应用程序[todo-list]似乎启动了一个名为[Druid-ConnectionPool-Create-2023152835]的线程,但未能停止它。这很可能会造成内存泄漏。线程的堆栈跟踪:[ sun.misc.Unsafe.park(Native Method) java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039) com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:2813)]
日志全文
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: Server.服务器版本: Apache Tomcat/8.5.83
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 服务器构建: Oct 3 2022 21:11:09 UTC
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 服务器版本号: 8.5.83.0
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 操作系统名称: Windows 10
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: OS.版本: 10.0
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 架构: amd64
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: Java 环境变量: C:\Program Files\Java\jdk1.8.0_301\jre
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: Java虚拟机版本: 1.8.0_301-b09
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: JVM.供应商: Oracle Corporation
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: CATALINA_BASE: E:\temp1\tomcat-server-location
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: CATALINA_HOME: F:\bin_java\apache-tomcat-8.5.83
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行参数: -agentlib:jdwp=transport=dt_socket,suspend=y,address=localhost:52079
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行参数: -javaagent:C:\Users\lawsssscat\Desktop\sts-4.16.1.RELEASE\configuration\org.eclipse.osgi\268\0\.cp\lib\javaagent-shaded.jar
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行参数: -Dcatalina.base=E:\temp1\tomcat-server-location
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行参数: -Dcatalina.home=F:\bin_java\apache-tomcat-8.5.83
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行参数: -Dwtp.deploy=E:\temp1\tomcat-server-location\wtpwebapps
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行参数: -Djava.endorsed.dirs=F:\bin_java\apache-tomcat-8.5.83\endorsed
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行参数: -Dfile.encoding=UTF-8
十一月 25, 2022 8:56:00 下午 org.apache.catalina.core.AprLifecycleListener lifecycleEvent
信息: 在java.library.path:[C:\Program Files\Java\jdk1.8.0_301\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;C:\Program Files\Java\jdk1.8.0_301\jre\bin;C:/Users/lawsssscat/Desktop/sts-4.16.1.RELEASE//plugins/org.eclipse.justj.openjdk.hotspot.jre.full.win32.x86_64_17.0.4.v20221004-1257/jre/bin/server;C:/Users/lawsssscat/Desktop/sts-4.16.1.RELEASE//plugins/org.eclipse.justj.openjdk.hotspot.jre.full.win32.x86_64_17.0.4.v20221004-1257/jre/bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files\Git\cmd;C:\Program Files\Git\bin;C:\Program Files\nodejs\;C:\Program Files (x86)\Tencent\微信web开发者工具\dll;C:\Program Files\dotnet\;C:\Program Files\lua;C:\Program Files\luarocks;C:\MinGW\bin;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\NVIDIA Corporation\NVIDIA NvDLISR;C:\Program Files\MySQL\MySQL Utilities 1.6\;C:\Program Files\MySQL\MySQL Shell 8.0\bin\;C:\Ruby31-x64\bin;C:\Ruby24-x64\bin;C:\Users\lawsssscat\AppData\Local\Microsoft\WindowsApps;C:\Program Files\qemu;C:\Users\lawsssscat\AppData\Roaming\npm;C:\Users\lawsssscat\AppData\Local\Programs\Microsoft VS Code\bin;C:\Program Files\ffmpeg\bin;E:\nodejs\node_global;C:\Users\lawsssscat\AppData\Local\GitHubDesktop\bin;C:\Users\lawsssscat\AppData\Local\Programs\Python\Python310;C:\Users\lawsssscat\Desktop\cmder;C:\cmake\bin;C:\bash_extend;F:\bin_java\apache-maven-3.8.6\bin;C:\Program Files\Java\jdk1.8.0_301\bin;F:\bin_db\mysql-8.0.31-winx64\bin;;C:\Users\lawsssscat\Desktop\sts-4.16.1.RELEASE;;.]上找不到基于APR的Apache Tomcat本机库,该库允许在生产环境中获得最佳性能
十一月 25, 2022 8:56:00 下午 org.apache.coyote.AbstractProtocol init
信息: 初始化协议处理器 ["http-nio-8080"]
十一月 25, 2022 8:56:00 下午 org.apache.catalina.startup.Catalina load
信息: Initialization processed in 418 ms
十一月 25, 2022 8:56:00 下午 org.apache.catalina.core.StandardService startInternal
信息: 正在启动服务[Catalina]
十一月 25, 2022 8:56:00 下午 org.apache.catalina.core.StandardEngine startInternal
信息: 正在启动 Servlet 引擎:[Apache Tomcat/8.5.83]
十一月 25, 2022 8:56:00 下午 org.apache.jasper.servlet.TldScanner scanJars
信息: 至少有一个JAR被扫描用于TLD但尚未包含TLD。 为此记录器启用调试日志记录,以获取已扫描但未在其中找到TLD的完整JAR列表。 在扫描期间跳过不需要的JAR可以缩短启动时间和JSP编译时间。
十一月 25, 2022 8:56:01 下午 org.apache.catalina.util.SessionIdGeneratorBase createSecureRandom
警告: 使用[SHA1PRNG]创建会话ID生成的SecureRandom实例花费了[172]毫秒。
十一月 25, 2022 8:56:01 下午 org.apache.jasper.servlet.TldScanner scanJars
信息: 至少有一个JAR被扫描用于TLD但尚未包含TLD。 为此记录器启用调试日志记录,以获取已扫描但未在其中找到TLD的完整JAR列表。 在扫描期间跳过不需要的JAR可以缩短启动时间和JSP编译时间。
十一月 25, 2022 8:56:01 下午 org.apache.catalina.startup.HostConfig deployDirectory
信息: 把web 应用程序部署到目录 [E:\temp1\tomcat-server-location\webapps\todo-list-pkg]
十一月 25, 2022 8:56:01 下午 org.apache.jasper.servlet.TldScanner scanJars
信息: 至少有一个JAR被扫描用于TLD但尚未包含TLD。 为此记录器启用调试日志记录,以获取已扫描但未在其中找到TLD的完整JAR列表。 在扫描期间跳过不需要的JAR可以缩短启动时间和JSP编译时间。
十一月 25, 2022 8:56:01 下午 org.apache.catalina.startup.HostConfig deployDirectory
信息: Web应用程序目录[E:\temp1\tomcat-server-location\webapps\todo-list-pkg]的部署已在[316]毫秒内完成
十一月 25, 2022 8:56:01 下午 org.apache.coyote.AbstractProtocol start
信息: 开始协议处理句柄["http-nio-8080"]
十一月 25, 2022 8:56:01 下午 org.apache.catalina.startup.Catalina start
信息: Server startup in 1174 ms
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
十一月 25, 2022 8:56:06 下午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
十一月 25, 2022 8:56:52 下午 org.apache.catalina.core.StandardContext reload
信息: 已开始重新加载名为[/todo-list]的上下文
十一月 25, 2022 8:56:52 下午 org.apache.catalina.loader.WebappClassLoaderBase clearReferencesJdbc
警告: Web应用程序 [todo-list] 注册了JDBC驱动程序 [com.alibaba.druid.proxy.DruidDriver],但在Web应用程序停止时无法注销它。 为防止内存泄漏,JDBC驱动程序已被强制取消注册。
十一月 25, 2022 8:56:52 下午 org.apache.catalina.loader.WebappClassLoaderBase clearReferencesJdbc
警告: Web应用程序 [todo-list] 注册了JDBC驱动程序 [com.mysql.jdbc.Driver],但在Web应用程序停止时无法注销它。 为防止内存泄漏,JDBC驱动程序已被强制取消注册。
十一月 25, 2022 8:56:52 下午 org.apache.catalina.loader.WebappClassLoaderBase clearReferencesThreads
警告: Web应用程序[todo-list]似乎启动了一个名为[Abandoned connection cleanup thread]的线程,但未能停止它。这很可能会造成内存泄漏。线程的堆栈跟踪:[
java.lang.Object.wait(Native Method)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
com.mysql.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:43)]
十一月 25, 2022 8:56:52 下午 org.apache.catalina.loader.WebappClassLoaderBase clearReferencesThreads
警告: Web应用程序[todo-list]似乎启动了一个名为[Druid-ConnectionPool-Create-2023152835]的线程,但未能停止它。这很可能会造成内存泄漏。线程的堆栈跟踪:[
sun.misc.Unsafe.park(Native Method)
java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:2813)]
十一月 25, 2022 8:56:52 下午 org.apache.catalina.loader.WebappClassLoaderBase clearReferencesThreads
警告: Web应用程序[todo-list]似乎启动了一个名为[Druid-ConnectionPool-Destroy-2023152835]的线程,但未能停止它。这很可能会造成内存泄漏。线程的堆栈跟踪:[
java.lang.Thread.sleep(Native Method)
com.alibaba.druid.pool.DruidDataSource$DestroyConnectionThread.run(DruidDataSource.java:2913)]
十一月 25, 2022 8:56:52 下午 org.apache.jasper.servlet.TldScanner scanJars
信息: 至少有一个JAR被扫描用于TLD但尚未包含TLD。 为此记录器启用调试日志记录,以获取已扫描但未在其中找到TLD的完整JAR列表。 在扫描期间跳过不需要的JAR可以缩短启动时间和JSP编译时间。
十一月 25, 2022 8:56:52 下午 org.apache.catalina.core.StandardContext reload
信息: 已完成重新加载名为[/todo-list]的上下文
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
十一月 25, 2022 9:05:20 下午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
查看数据库连接,确实有问题:
- 每次连接数据库会创建10个连接(这应该正常,线程池)
- 长时间(大概10min)不与数据库交互,数据库连接并没有断开(这也没啥。问题是下面)
- 一段时间后,再次访问数据库,会创建新的10个连接。问题是,旧的10个连接并不会关闭!
- 程序长时间运行的结果是,创建了一堆与数据库的连接,而只有其中10个在工作。
- 直到程序关闭,数据库连接才断开
连接配置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://192.168.1.7777:111111/xxxxx
username=bbbb
password=xxxxx
initialSize=10
maxActive=20
maxWait=10000
获取、销毁连接代码
package com.lawsssscat.web.util;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
/**
*
* 1. 从数据源获取数据库连接
* 2. 将数据源绑定到ThreadLocal
* 3. 释放线程时和本地线程解除绑定
*
* @author lawsssscat
*
*/
public class JDBCUtils {
// 数据源成员变量设置为静态资源,单例性
private static DataSource dataSource;
// 由于ThreadLocal对象需要作为绑定数据时的key从线程key-value对中获取数据,因此,要保证唯一性
// 加static声明为静态资源既可保证唯一性
final private static ThreadLocal<Connection> connectionThreadLocal = new ThreadLocal<>();
// 在静态代码块中初始化数据源
static {
// 从 jdbc.properties 文件中读取数据库的信息
// 基于WEB-INFO/classes(类路径根目录)获取配置文件,保证可移植性
// 1. 获取当前的类加载器
ClassLoader classLoader = JDBCUtils.class.getClassLoader();
// 2. 通过类加载器对象从类路径根目录下读取文件
InputStream stream = classLoader.getResourceAsStream("jdbc.properties");
// 3. 使用Properties类封装属性文件中的数据
Properties properties = new Properties();
try {
properties.load(stream);
//4. 根据Properties对象(已封装了数据库连接信息)
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
// 立即终止
throw new RuntimeException(e);
}
}
public static Connection getConnection() throws SQLException {
Connection connection = connectionThreadLocal.get();
if(connection==null) {
connection = dataSource.getConnection();
connectionThreadLocal.set(connection);
}
return connection;
}
public static void releaseConnection() throws SQLException {
Connection connection = connectionThreadLocal.get();
if(connection != null) {
// 将当前数据库连接从当前线程上移除
connectionThreadLocal.remove();
// 放后面,因为可能抛出错误!
connection.close();
}
}
}
filter 中获取连接
package com.lawsssscat.web.filter;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import com.lawsssscat.web.util.BooleanHelper;
import com.lawsssscat.web.util.JDBCUtils;
import com.lawsssscat.web.util.WebHelper;
import com.lawsssscat.web.util.WebVariable;
public class TransactionFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 静态资源跳过处理
if(BooleanHelper.isTrue(WebHelper.getRequestVariable(WebVariable.REQUEST_STATIC_RESOURCE))) {
chain.doFilter(request, response);
return;
}
// 获取数据库连接
// ⭐️ 重要:需要保证参与事务的多个数据库操作(SQL语句)使用的是同一个数据库连接
Connection connection = null;
try {
connection = JDBCUtils.getConnection();
// 取消自动提交
connection.setAutoCommit(false);
// 业务处理
chain.doFilter(request, response);
// 业务处理成功,提交事务
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
try {
// 业务处理失败,回滚事务
connection.rollback();
} catch (SQLException e1) {
// TODO mark
e1.printStackTrace();
}
} finally {
try {
JDBCUtils.releaseConnection();
} catch (SQLException e) {
// TODO mark
e.printStackTrace();
}
}
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}