From 981c995691041f888edbdc11a3f7f63dafcd967d Mon Sep 17 00:00:00 2001
From: "1437892690@qq.com" <1437892690@qq.com>
Date: Thu, 13 Nov 2025 10:43:28 +0800
Subject: [PATCH 01/18] =?UTF-8?q?[=E5=8A=9F=E8=83=BD]=20=E6=95=B0=E6=8D=AE?=
=?UTF-8?q?=E5=BA=93=E8=BF=9E=E6=8E=A5=E6=B1=A0=E8=8E=B7=E5=8F=96=E4=B8=8D?=
=?UTF-8?q?=E5=88=B0=E8=BF=9E=E6=8E=A5=E6=97=B6=E8=AE=B0=E5=BD=95=E6=8C=81?=
=?UTF-8?q?=E6=9C=89=E8=BF=9E=E6=8E=A5=E7=9A=84=E7=BA=BF=E7=A8=8B=E4=BF=A1?=
=?UTF-8?q?=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
关联 #[1551594485678080]数据库连接池获取不到连接时记录持有连接的线程信息 http://192.168.0.96:8090/demo/rdm.html#/story-detail/939050947543040/939050947543042/1551594485678080
---
.../framework/logback/logback-base.xml | 33 ++
.../store/mysql/NeatLogicBasicDataSource.java | 86 ++++-
.../store/mysql/NeatLogicConnection.java | 329 ++++++++++++++++++
3 files changed, 446 insertions(+), 2 deletions(-)
create mode 100644 src/main/java/neatlogic/framework/store/mysql/NeatLogicConnection.java
diff --git a/src/main/java/neatlogic/framework/logback/logback-base.xml b/src/main/java/neatlogic/framework/logback/logback-base.xml
index de34ead75..e981a2466 100644
--- a/src/main/java/neatlogic/framework/logback/logback-base.xml
+++ b/src/main/java/neatlogic/framework/logback/logback-base.xml
@@ -277,6 +277,36 @@
true
+
+ ${log4j.home}/SQLTransientConnectionException.log
+
+ ${log4j.home}/SQLTransientConnectionException.log.%i
+ 1
+ 5
+
+
+ ERROR
+ ACCEPT
+ DENY
+
+
+ 100MB
+
+
+ [%-5level]%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %logger{36}[%line] [%tenant] %requestUrl- %msg%n
+
+
+
+
+
+
+ 0
+ 50
+
+ true
+
+
${log4j.home}/sqlTimeout.log
@@ -357,6 +387,9 @@
+
+
+
diff --git a/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java b/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
index 097435a98..5b693dbc4 100644
--- a/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
+++ b/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
@@ -14,22 +14,104 @@ package neatlogic.framework.store.mysql;
import com.zaxxer.hikari.HikariDataSource;
import neatlogic.framework.asynchronization.threadlocal.UserContext;
+import neatlogic.framework.common.config.Config;
import neatlogic.framework.common.util.RC4Util;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.jdbc.CannotGetJdbcConnectionException;
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
import java.sql.Connection;
import java.sql.SQLException;
+import java.sql.SQLTransientConnectionException;
import java.sql.Statement;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
public class NeatLogicBasicDataSource extends HikariDataSource {//替换dbcp2的BasicDataSource
- private final Logger logger = LoggerFactory.getLogger(NeatLogicBasicDataSource.class);
+ private static final Logger logger = LoggerFactory.getLogger(NeatLogicBasicDataSource.class);
+
+ // 保存上次查询ShowProcesslist命令的时间毫秒数
+ private static volatile long lastShowProcesslistMilliseconds = -1;
+ // 持有数据库连接的线程Map
+ private final static Map holdingConnectionThreadMap = new ConcurrentHashMap<>();
+
+ public static void addHoldingConnectionThreadByConnection(Connection connection) {
+ int size = holdingConnectionThreadMap.size();
+ if (size <= Config.DATASOURCE_MAXIMUN_POOL_SIZE()) {
+ holdingConnectionThreadMap.put(connection, Thread.currentThread());
+ } else {
+ logger.error("持有数据库连接的线程Map大小为{}, 数据库连接池最大数量为{}", size, Config.DATASOURCE_MAXIMUN_POOL_SIZE());
+ }
+ }
+
+ public static Thread removeHoldingConnectionThreadByConnection(Connection connection) {
+ return holdingConnectionThreadMap.remove(connection);
+ }
+
+ public static String getHoldingConnectionThreadStackTrace(Map holdingConnectionThreadMap) {
+ ThreadMXBean mxBean = ManagementFactory.getThreadMXBean();
+ ThreadInfo[] threadInfos = mxBean.getThreadInfo(mxBean.getAllThreadIds(), 0);
+ Map threadInfoMap = new HashMap<>();
+ for (ThreadInfo threadInfo : threadInfos) {
+ threadInfoMap.put(threadInfo.getThreadId(), threadInfo);
+ }
+ StringBuilder stringBuilder = new StringBuilder(System.lineSeparator());
+ stringBuilder.append("总线程数为: ").append(holdingConnectionThreadMap.size()).append(System.lineSeparator());
+ for (Map.Entry entry : holdingConnectionThreadMap.entrySet()) {
+ Thread thread = entry.getValue();
+ stringBuilder.append("[").append(thread.getName()).append("] prio=").append(thread.getPriority())
+ .append(" tid=").append(thread.getId())
+ .append(" ").append(thread.getState())
+ .append(" ").append(thread.isDaemon() ? "deamon" : "worker");
+ ThreadInfo threadInfo = threadInfoMap.get(thread.getId());
+ if (threadInfo != null) {
+ stringBuilder.append(" native=").append(threadInfo.isInNative())
+ .append(", suspended=").append(threadInfo.isSuspended())
+ .append(", block=").append(threadInfo.getBlockedCount())
+ .append(", wait=").append(threadInfo.getWaitedCount())
+ .append(" lock=").append(threadInfo.getLockName())
+ .append(" owned by ").append(threadInfo.getLockOwnerName())
+ .append(" (").append(threadInfo.getLockOwnerId())
+ .append("), cpu=").append(mxBean.getThreadCpuTime(threadInfo.getThreadId()) / 1000000L)
+ .append(", user=").append(mxBean.getThreadUserTime(threadInfo.getThreadId()) / 1000000L);
+ }
+ stringBuilder.append(System.lineSeparator());
+ StackTraceElement[] stackTrace = thread.getStackTrace();
+ for (StackTraceElement stackTraceElement : stackTrace) {
+ stringBuilder.append(" at ").append(stackTraceElement).append(System.lineSeparator());
+ }
+ }
+ return stringBuilder.toString();
+ }
+
+ private synchronized void audit(Map holdingConnectionThreadMap) {
+ long currentTimeMillis = System.currentTimeMillis();
+ long interval = currentTimeMillis - lastShowProcesslistMilliseconds;
+ if (interval > TimeUnit.MINUTES.toMillis(1)) {
+ lastShowProcesslistMilliseconds = currentTimeMillis;
+ Logger SQLTransientConnectionExceptionAuditLogger = LoggerFactory.getLogger("SQLTransientConnectionExceptionAudit");
+ SQLTransientConnectionExceptionAuditLogger.error(getHoldingConnectionThreadStackTrace(holdingConnectionThreadMap));
+ }
+ }
@Override
public Connection getConnection() throws SQLException {
- Connection conn = super.getConnection();
+ Connection conn = null;
+ try {
+ conn = super.getConnection();
+ addHoldingConnectionThreadByConnection(conn);
+ conn = new NeatLogicConnection(conn);
+ } catch (CannotGetJdbcConnectionException | SQLTransientConnectionException ex) {
+ audit(new HashMap<>(holdingConnectionThreadMap));
+ throw ex;
+ }
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
try (Statement statement = conn.createStatement()) {
if (Objects.equals(DatasourceManager.getDatabaseId(), DatabaseVendor.MYSQL.getDatabaseId())) {
diff --git a/src/main/java/neatlogic/framework/store/mysql/NeatLogicConnection.java b/src/main/java/neatlogic/framework/store/mysql/NeatLogicConnection.java
new file mode 100644
index 000000000..73ce446e4
--- /dev/null
+++ b/src/main/java/neatlogic/framework/store/mysql/NeatLogicConnection.java
@@ -0,0 +1,329 @@
+/*
+ *
+ * Copyright (C) 2025 TechSure Co., Ltd. All Rights Reserved.
+ * This file is part of the NeatLogic software.
+ * Licensed under the NeatLogic Sustainable Use License (NSUL), Version 4.x – 2025.
+ * You may use this file only in compliance with the License.
+ * See the LICENSE file distributed with this work for the full license text.
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+package neatlogic.framework.store.mysql;
+
+import java.sql.*;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.Executor;
+
+public class NeatLogicConnection implements Connection {
+
+ private final Connection connection;
+
+ public NeatLogicConnection(Connection connection) {
+ this.connection = connection;
+ }
+
+ @Override
+ public Statement createStatement() throws SQLException {
+ return this.connection.createStatement();
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql) throws SQLException {
+ return this.connection.prepareStatement(sql);
+ }
+
+ @Override
+ public CallableStatement prepareCall(String sql) throws SQLException {
+ return this.connection.prepareCall(sql);
+ }
+
+ @Override
+ public String nativeSQL(String sql) throws SQLException {
+ return this.connection.nativeSQL(sql);
+ }
+
+ @Override
+ public void setAutoCommit(boolean autoCommit) throws SQLException {
+ this.connection.setAutoCommit(autoCommit);
+ }
+
+ @Override
+ public boolean getAutoCommit() throws SQLException {
+ return this.connection.getAutoCommit();
+ }
+
+ @Override
+ public void commit() throws SQLException {
+ this.connection.commit();
+ }
+
+ @Override
+ public void rollback() throws SQLException {
+ this.connection.rollback();
+ }
+
+ @Override
+ public void close() throws SQLException {
+ NeatLogicBasicDataSource.removeHoldingConnectionThreadByConnection(this.connection);
+ this.connection.close();
+ }
+
+ @Override
+ public boolean isClosed() throws SQLException {
+ return this.connection.isClosed();
+ }
+
+ @Override
+ public DatabaseMetaData getMetaData() throws SQLException {
+ return this.connection.getMetaData();
+ }
+
+ @Override
+ public void setReadOnly(boolean readOnly) throws SQLException {
+ this.connection.setReadOnly(readOnly);
+ }
+
+ @Override
+ public boolean isReadOnly() throws SQLException {
+ return this.connection.isReadOnly();
+ }
+
+ @Override
+ public void setCatalog(String catalog) throws SQLException {
+ this.connection.setCatalog(catalog);
+ }
+
+ @Override
+ public String getCatalog() throws SQLException {
+ return this.connection.getCatalog();
+ }
+
+ @Override
+ public void setTransactionIsolation(int level) throws SQLException {
+ this.connection.setTransactionIsolation(level);
+ }
+
+ @Override
+ public int getTransactionIsolation() throws SQLException {
+ return this.connection.getTransactionIsolation();
+ }
+
+ @Override
+ public SQLWarning getWarnings() throws SQLException {
+ return this.connection.getWarnings();
+ }
+
+ @Override
+ public void clearWarnings() throws SQLException {
+ this.connection.clearWarnings();
+ }
+
+ @Override
+ public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
+ return this.connection.createStatement(resultSetType, resultSetConcurrency);
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
+ return this.connection.prepareStatement(sql, resultSetType, resultSetConcurrency);
+ }
+
+ @Override
+ public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
+ return this.connection.prepareCall(sql, resultSetType, resultSetConcurrency);
+ }
+
+ @Override
+ public Map> getTypeMap() throws SQLException {
+ return this.connection.getTypeMap();
+ }
+
+ @Override
+ public void setTypeMap(Map> map) throws SQLException {
+ this.connection.setTypeMap(map);
+ }
+
+ @Override
+ public void setHoldability(int holdability) throws SQLException {
+ this.connection.setHoldability(holdability);
+ }
+
+ @Override
+ public int getHoldability() throws SQLException {
+ return this.connection.getHoldability();
+ }
+
+ @Override
+ public Savepoint setSavepoint() throws SQLException {
+ return this.connection.setSavepoint();
+ }
+
+ @Override
+ public Savepoint setSavepoint(String name) throws SQLException {
+ return this.connection.setSavepoint(name);
+ }
+
+ @Override
+ public void rollback(Savepoint savepoint) throws SQLException {
+ this.connection.rollback(savepoint);
+ }
+
+ @Override
+ public void releaseSavepoint(Savepoint savepoint) throws SQLException {
+ this.connection.releaseSavepoint(savepoint);
+ }
+
+
+ @Override
+ public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+ return this.connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+ return this.connection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
+ }
+
+ @Override
+ public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+ return this.connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
+ return this.connection.prepareStatement(sql, autoGeneratedKeys);
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
+ return this.connection.prepareStatement(sql, columnIndexes);
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
+ return this.connection.prepareStatement(sql, columnNames);
+ }
+
+ @Override
+ public Clob createClob() throws SQLException {
+ return this.connection.createClob();
+ }
+
+ @Override
+ public Blob createBlob() throws SQLException {
+ return this.connection.createBlob();
+ }
+
+ @Override
+ public NClob createNClob() throws SQLException {
+ return this.connection.createNClob();
+ }
+
+ @Override
+ public SQLXML createSQLXML() throws SQLException {
+ return this.connection.createSQLXML();
+ }
+
+ @Override
+ public boolean isValid(int timeout) throws SQLException {
+ return this.connection.isValid(timeout);
+ }
+
+ @Override
+ public void setClientInfo(String name, String value) throws SQLClientInfoException {
+ this.connection.setClientInfo(name, value);
+ }
+
+ @Override
+ public void setClientInfo(Properties properties) throws SQLClientInfoException {
+ this.connection.setClientInfo(properties);
+ }
+
+ @Override
+ public String getClientInfo(String name) throws SQLException {
+ return this.connection.getClientInfo(name);
+ }
+
+ @Override
+ public Properties getClientInfo() throws SQLException {
+ return this.connection.getClientInfo();
+ }
+
+ @Override
+ public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
+ return this.connection.createArrayOf(typeName, elements);
+ }
+
+ @Override
+ public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
+ return this.connection.createStruct(typeName, attributes);
+ }
+
+ @Override
+ public void setSchema(String schema) throws SQLException {
+ this.connection.setSchema(schema);
+ }
+
+ @Override
+ public String getSchema() throws SQLException {
+ return this.connection.getSchema();
+ }
+
+ @Override
+ public void abort(Executor executor) throws SQLException {
+ this.connection.abort(executor);
+ }
+
+ @Override
+ public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
+ this.connection.setNetworkTimeout(executor, milliseconds);
+ }
+
+ @Override
+ public int getNetworkTimeout() throws SQLException {
+ return this.connection.getNetworkTimeout();
+ }
+
+ @Override
+ public void beginRequest() throws SQLException {
+ this.connection.beginRequest();
+ }
+
+ @Override
+ public void endRequest() throws SQLException {
+ this.connection.endRequest();
+ }
+
+ @Override
+ public boolean setShardingKeyIfValid(ShardingKey shardingKey, ShardingKey superShardingKey, int timeout) throws SQLException {
+ return this.connection.setShardingKeyIfValid(shardingKey, superShardingKey, timeout);
+ }
+
+ @Override
+ public boolean setShardingKeyIfValid(ShardingKey shardingKey, int timeout) throws SQLException {
+ return this.connection.setShardingKeyIfValid(shardingKey, timeout);
+ }
+
+ @Override
+ public void setShardingKey(ShardingKey shardingKey, ShardingKey superShardingKey) throws SQLException {
+ this.connection.setShardingKey(shardingKey, superShardingKey);
+ }
+
+ @Override
+ public void setShardingKey(ShardingKey shardingKey) throws SQLException {
+ this.connection.setShardingKey(shardingKey);
+ }
+
+ @Override
+ public T unwrap(Class iface) throws SQLException {
+ return this.connection.unwrap(iface);
+ }
+
+ @Override
+ public boolean isWrapperFor(Class> iface) throws SQLException {
+ return this.connection.isWrapperFor(iface);
+ }
+}
--
Gitee
From 990c00bcc764efd9e69ed09aeb44f3a846f1b545 Mon Sep 17 00:00:00 2001
From: "1437892690@qq.com" <1437892690@qq.com>
Date: Fri, 14 Nov 2025 18:49:17 +0800
Subject: [PATCH 02/18] =?UTF-8?q?[=E5=8A=9F=E8=83=BD]=20=E6=95=B0=E6=8D=AE?=
=?UTF-8?q?=E5=BA=93=E8=BF=9E=E6=8E=A5=E6=B1=A0=E8=8E=B7=E5=8F=96=E4=B8=8D?=
=?UTF-8?q?=E5=88=B0=E8=BF=9E=E6=8E=A5=E6=97=B6=E8=AE=B0=E5=BD=95=E6=8C=81?=
=?UTF-8?q?=E6=9C=89=E8=BF=9E=E6=8E=A5=E7=9A=84=E7=BA=BF=E7=A8=8B=E4=BF=A1?=
=?UTF-8?q?=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
关联 #[1551594485678080]数据库连接池获取不到连接时记录持有连接的线程信息 http://192.168.0.96:8090/demo/rdm.html#/story-detail/939050947543040/939050947543042/1551594485678080
---
.../neatlogic/framework/common/config/Config.java | 12 +++++++++---
.../store/mysql/NeatLogicBasicDataSource.java | 10 +++++++---
2 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/src/main/java/neatlogic/framework/common/config/Config.java b/src/main/java/neatlogic/framework/common/config/Config.java
index 4ed2d325a..d74752aac 100644
--- a/src/main/java/neatlogic/framework/common/config/Config.java
+++ b/src/main/java/neatlogic/framework/common/config/Config.java
@@ -54,7 +54,7 @@ public class Config {
private static String DB_HOST;
private static Integer DB_PORT;
private static String DB_URL;
- private static String DB_TRANSACTION_TIMEOUT;// 事务超时时间
+ private static Integer DB_TRANSACTION_TIMEOUT;// 事务超时时间
private static int DATASOURCE_CONNECT_TIMEOUT;//连接池连接超时时间
private static Integer DATASOURCE_MAXIMUM_POOL_SIZE;//连接数
private static Integer DATASOURCE_MAX_LIFETIME;//控制池中连接的最大生存期
@@ -62,6 +62,7 @@ public class Config {
private static Integer DATASOURCE_VALIDATION_TIMEOUT;//此属性控制测试连接是否活跃的最长时间。此值必须小于 connectionTimeout
private static Integer DATASOURCE_IDLE_TIMEOUT;//此属性控制允许连接在池中处于空闲状态的最长时间
private static Long DATASOURCE_KEEPALIVE_TIME;//此属性控制允许连接在池中心跳时间,不能比DATASOURCE_MAX_LIFETIME大
+ private static Boolean DATASOURCE_CONNECTION_HOLDER_TRACK_ENABLE; // 数据库连接持有者(线程)跟踪开启
private static String DATA_HOME;// 存储文件路径
private static String AUDIT_HOME;// 审计日志存储文件路径
private static int SERVER_HEARTBEAT_RATE;// 心跳频率
@@ -249,7 +250,7 @@ public class Config {
return DB_URL;
}
- public static String DB_TRANSACTION_TIMEOUT() {// root-context.xml中使用了该变量
+ public static Integer DB_TRANSACTION_TIMEOUT() {// root-context.xml中使用了该变量
return DB_TRANSACTION_TIMEOUT;
}
@@ -281,6 +282,10 @@ public class Config {
return DATASOURCE_IDLE_TIMEOUT;
}
+ public static boolean DATASOURCE_CONNECTION_HOLDER_TRACK_ENABLE() {
+ return DATASOURCE_CONNECTION_HOLDER_TRACK_ENABLE;
+ }
+
public static String JMS_URL() {
return JMS_URL;
}
@@ -628,7 +633,7 @@ public class Config {
USER_EXPIRETIME = prop.getProperty("user.expiretime", "60");
LOGIN_CAPTCHA_EXPIRED_TIME = Integer.parseInt(prop.getProperty("login.captcha.expired.time", "60"));
LOGIN_FAILED_TIMES_CAPTCHA = Integer.parseInt(prop.getProperty("login.failed.times.captcha", "3"));
- DB_TRANSACTION_TIMEOUT = prop.getProperty("db.transaction.timeout");
+ DB_TRANSACTION_TIMEOUT = Integer.parseInt(prop.getProperty("db.transaction.timeout"));
DATASOURCE_CONNECT_TIMEOUT = Integer.parseInt(prop.getProperty("datasource.connect.timeout", "5000"));
DATASOURCE_MAXIMUM_POOL_SIZE = Integer.parseInt(prop.getProperty("datasource.maximum.pool.size", "250"));
DATASOURCE_KEEPALIVE_TIME = Long.parseLong(prop.getProperty("datasource.keepalive.time", "180000"));
@@ -636,6 +641,7 @@ public class Config {
DATASOURCE_MINIMUM_IDLE = Integer.parseInt(prop.getProperty("datasource.minimum.idle", "20"));
DATASOURCE_VALIDATION_TIMEOUT = Integer.parseInt(prop.getProperty("datasource.validation.timeout", "5000"));
DATASOURCE_IDLE_TIMEOUT = Integer.parseInt(prop.getProperty("datasource.idle.timeout", "600000"));
+ DATASOURCE_CONNECTION_HOLDER_TRACK_ENABLE = Boolean.parseBoolean(prop.getProperty("datasource.connection.holder.track.enable", "true"));
DB_URL = prop.getProperty("db.url");
DB_HOST = prop.getProperty("db.host", "localhost");
DB_PORT = Integer.parseInt(prop.getProperty("db.port", "3306"));
diff --git a/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java b/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
index 5b693dbc4..0b30fe1c7 100644
--- a/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
+++ b/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
@@ -106,10 +106,14 @@ public class NeatLogicBasicDataSource extends HikariDataSource {//替换dbcp2的
Connection conn = null;
try {
conn = super.getConnection();
- addHoldingConnectionThreadByConnection(conn);
- conn = new NeatLogicConnection(conn);
+ if (Config.DATASOURCE_CONNECTION_HOLDER_TRACK_ENABLE()) {
+ addHoldingConnectionThreadByConnection(conn);
+ conn = new NeatLogicConnection(conn);
+ }
} catch (CannotGetJdbcConnectionException | SQLTransientConnectionException ex) {
- audit(new HashMap<>(holdingConnectionThreadMap));
+ if (Config.DATASOURCE_CONNECTION_HOLDER_TRACK_ENABLE()) {
+ audit(new HashMap<>(holdingConnectionThreadMap));
+ }
throw ex;
}
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
--
Gitee
From db8629224a4437ee8f83fb71adcc871f82c6670f Mon Sep 17 00:00:00 2001
From: "1437892690@qq.com" <1437892690@qq.com>
Date: Mon, 17 Nov 2025 18:23:58 +0800
Subject: [PATCH 03/18] =?UTF-8?q?[=E5=8A=9F=E8=83=BD]=20=E6=95=B0=E6=8D=AE?=
=?UTF-8?q?=E5=BA=93=E8=BF=9E=E6=8E=A5=E6=B1=A0=E8=8E=B7=E5=8F=96=E4=B8=8D?=
=?UTF-8?q?=E5=88=B0=E8=BF=9E=E6=8E=A5=E6=97=B6=E8=AE=B0=E5=BD=95=E7=BA=BF?=
=?UTF-8?q?=E7=A8=8B=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
关联 #[1551594485678080]数据库连接池获取不到连接时记录线程信息 http://192.168.0.96:8090/demo/rdm.html#/story-detail/939050947543040/939050947543042/1551594485678080
---
.../threadlocal/InterceptorContext.java | 75 ++++
.../framework/common/config/Config.java | 12 +-
.../framework/dao/config/mybatis-config.xml | 1 +
.../dao/plugin/DataSchemaInterceptor.java | 6 +-
.../dao/plugin/ExecutingSQLInterceptor.java | 63 ++++
...ModifyResultMapTypeHandlerInterceptor.java | 10 +-
.../dao/plugin/SqlCostInterceptor.java | 65 ++--
.../dao/plugin/ThreadLocalInterceptor.java | 44 +++
.../store/mysql/NeatLogicBasicDataSource.java | 104 ++----
.../store/mysql/NeatLogicConnection.java | 329 ------------------
.../neatlogic/framework/util/ThreadUtil.java | 59 ++++
11 files changed, 323 insertions(+), 445 deletions(-)
create mode 100644 src/main/java/neatlogic/framework/asynchronization/threadlocal/InterceptorContext.java
create mode 100644 src/main/java/neatlogic/framework/dao/plugin/ExecutingSQLInterceptor.java
create mode 100644 src/main/java/neatlogic/framework/dao/plugin/ThreadLocalInterceptor.java
delete mode 100644 src/main/java/neatlogic/framework/store/mysql/NeatLogicConnection.java
create mode 100644 src/main/java/neatlogic/framework/util/ThreadUtil.java
diff --git a/src/main/java/neatlogic/framework/asynchronization/threadlocal/InterceptorContext.java b/src/main/java/neatlogic/framework/asynchronization/threadlocal/InterceptorContext.java
new file mode 100644
index 000000000..304b4993e
--- /dev/null
+++ b/src/main/java/neatlogic/framework/asynchronization/threadlocal/InterceptorContext.java
@@ -0,0 +1,75 @@
+/*
+ *
+ * *
+ * * Copyright (C) 2025 TechSure Co., Ltd. All Rights Reserved.
+ * * This file is part of the NeatLogic software.
+ * * Licensed under the NeatLogic Sustainable Use License (NSUL), Version 4.x – 2025.
+ * * You may use this file only in compliance with the License.
+ * * See the LICENSE file distributed with this work for the full license text.
+ * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * *
+ *
+ */
+
+package neatlogic.framework.asynchronization.threadlocal;
+
+import org.apache.ibatis.mapping.MappedStatement;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+public class InterceptorContext implements Serializable {
+
+ private static final ThreadLocal instance = new ThreadLocal<>();
+ @Serial
+ private static final long serialVersionUID = -5420998728515359636L;
+
+ private MappedStatement mappedStatement;
+
+ private Object parameter;
+ // 判断是否查询了数据库
+ private Boolean queryFromDatabase;
+
+ private InterceptorContext() {
+
+ }
+
+ public static InterceptorContext init() {
+ InterceptorContext interceptorContext = new InterceptorContext();
+ instance.set(interceptorContext);
+ return instance.get();
+ }
+
+ public static InterceptorContext get() {
+ return instance.get();
+ }
+
+ public void release() {
+ instance.remove();
+ }
+
+ public MappedStatement getMappedStatement() {
+ return mappedStatement;
+ }
+
+ public void setMappedStatement(MappedStatement mappedStatement) {
+ this.mappedStatement = mappedStatement;
+ }
+
+ public Object getParameter() {
+ return parameter;
+ }
+
+ public void setParameter(Object parameter) {
+ this.parameter = parameter;
+ }
+
+ public Boolean getQueryFromDatabase() {
+ return queryFromDatabase;
+ }
+
+ public void setQueryFromDatabase(Boolean queryFromDatabase) {
+ this.queryFromDatabase = queryFromDatabase;
+ }
+}
diff --git a/src/main/java/neatlogic/framework/common/config/Config.java b/src/main/java/neatlogic/framework/common/config/Config.java
index d74752aac..4ed2d325a 100644
--- a/src/main/java/neatlogic/framework/common/config/Config.java
+++ b/src/main/java/neatlogic/framework/common/config/Config.java
@@ -54,7 +54,7 @@ public class Config {
private static String DB_HOST;
private static Integer DB_PORT;
private static String DB_URL;
- private static Integer DB_TRANSACTION_TIMEOUT;// 事务超时时间
+ private static String DB_TRANSACTION_TIMEOUT;// 事务超时时间
private static int DATASOURCE_CONNECT_TIMEOUT;//连接池连接超时时间
private static Integer DATASOURCE_MAXIMUM_POOL_SIZE;//连接数
private static Integer DATASOURCE_MAX_LIFETIME;//控制池中连接的最大生存期
@@ -62,7 +62,6 @@ public class Config {
private static Integer DATASOURCE_VALIDATION_TIMEOUT;//此属性控制测试连接是否活跃的最长时间。此值必须小于 connectionTimeout
private static Integer DATASOURCE_IDLE_TIMEOUT;//此属性控制允许连接在池中处于空闲状态的最长时间
private static Long DATASOURCE_KEEPALIVE_TIME;//此属性控制允许连接在池中心跳时间,不能比DATASOURCE_MAX_LIFETIME大
- private static Boolean DATASOURCE_CONNECTION_HOLDER_TRACK_ENABLE; // 数据库连接持有者(线程)跟踪开启
private static String DATA_HOME;// 存储文件路径
private static String AUDIT_HOME;// 审计日志存储文件路径
private static int SERVER_HEARTBEAT_RATE;// 心跳频率
@@ -250,7 +249,7 @@ public class Config {
return DB_URL;
}
- public static Integer DB_TRANSACTION_TIMEOUT() {// root-context.xml中使用了该变量
+ public static String DB_TRANSACTION_TIMEOUT() {// root-context.xml中使用了该变量
return DB_TRANSACTION_TIMEOUT;
}
@@ -282,10 +281,6 @@ public class Config {
return DATASOURCE_IDLE_TIMEOUT;
}
- public static boolean DATASOURCE_CONNECTION_HOLDER_TRACK_ENABLE() {
- return DATASOURCE_CONNECTION_HOLDER_TRACK_ENABLE;
- }
-
public static String JMS_URL() {
return JMS_URL;
}
@@ -633,7 +628,7 @@ public class Config {
USER_EXPIRETIME = prop.getProperty("user.expiretime", "60");
LOGIN_CAPTCHA_EXPIRED_TIME = Integer.parseInt(prop.getProperty("login.captcha.expired.time", "60"));
LOGIN_FAILED_TIMES_CAPTCHA = Integer.parseInt(prop.getProperty("login.failed.times.captcha", "3"));
- DB_TRANSACTION_TIMEOUT = Integer.parseInt(prop.getProperty("db.transaction.timeout"));
+ DB_TRANSACTION_TIMEOUT = prop.getProperty("db.transaction.timeout");
DATASOURCE_CONNECT_TIMEOUT = Integer.parseInt(prop.getProperty("datasource.connect.timeout", "5000"));
DATASOURCE_MAXIMUM_POOL_SIZE = Integer.parseInt(prop.getProperty("datasource.maximum.pool.size", "250"));
DATASOURCE_KEEPALIVE_TIME = Long.parseLong(prop.getProperty("datasource.keepalive.time", "180000"));
@@ -641,7 +636,6 @@ public class Config {
DATASOURCE_MINIMUM_IDLE = Integer.parseInt(prop.getProperty("datasource.minimum.idle", "20"));
DATASOURCE_VALIDATION_TIMEOUT = Integer.parseInt(prop.getProperty("datasource.validation.timeout", "5000"));
DATASOURCE_IDLE_TIMEOUT = Integer.parseInt(prop.getProperty("datasource.idle.timeout", "600000"));
- DATASOURCE_CONNECTION_HOLDER_TRACK_ENABLE = Boolean.parseBoolean(prop.getProperty("datasource.connection.holder.track.enable", "true"));
DB_URL = prop.getProperty("db.url");
DB_HOST = prop.getProperty("db.host", "localhost");
DB_PORT = Integer.parseInt(prop.getProperty("db.port", "3306"));
diff --git a/src/main/java/neatlogic/framework/dao/config/mybatis-config.xml b/src/main/java/neatlogic/framework/dao/config/mybatis-config.xml
index ab4479288..aec63c08b 100644
--- a/src/main/java/neatlogic/framework/dao/config/mybatis-config.xml
+++ b/src/main/java/neatlogic/framework/dao/config/mybatis-config.xml
@@ -46,5 +46,6 @@ along with this program. If not, see .-->
+
diff --git a/src/main/java/neatlogic/framework/dao/plugin/DataSchemaInterceptor.java b/src/main/java/neatlogic/framework/dao/plugin/DataSchemaInterceptor.java
index 61b93c421..0f41d2405 100644
--- a/src/main/java/neatlogic/framework/dao/plugin/DataSchemaInterceptor.java
+++ b/src/main/java/neatlogic/framework/dao/plugin/DataSchemaInterceptor.java
@@ -12,6 +12,7 @@
package neatlogic.framework.dao.plugin;
+import neatlogic.framework.asynchronization.threadlocal.InterceptorContext;
import neatlogic.framework.asynchronization.threadlocal.TenantContext;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
@@ -31,7 +32,10 @@ public class DataSchemaInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
- SqlCostInterceptor.QUERY_FROM_DATABASE_INSTANCE.set(true);
+ InterceptorContext interceptorContext = InterceptorContext.get();
+ if (interceptorContext != null) {
+ interceptorContext.setQueryFromDatabase(true);
+ }
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
BoundSql boundSql = statementHandler.getBoundSql();
diff --git a/src/main/java/neatlogic/framework/dao/plugin/ExecutingSQLInterceptor.java b/src/main/java/neatlogic/framework/dao/plugin/ExecutingSQLInterceptor.java
new file mode 100644
index 000000000..a0d117595
--- /dev/null
+++ b/src/main/java/neatlogic/framework/dao/plugin/ExecutingSQLInterceptor.java
@@ -0,0 +1,63 @@
+/*
+ *
+ * *
+ * * Copyright (C) 2025 TechSure Co., Ltd. All Rights Reserved.
+ * * This file is part of the NeatLogic software.
+ * * Licensed under the NeatLogic Sustainable Use License (NSUL), Version 4.x – 2025.
+ * * You may use this file only in compliance with the License.
+ * * See the LICENSE file distributed with this work for the full license text.
+ * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * *
+ *
+ */
+
+package neatlogic.framework.dao.plugin;
+
+import neatlogic.framework.asynchronization.threadlocal.InterceptorContext;
+import org.apache.ibatis.executor.statement.StatementHandler;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.plugin.Interceptor;
+import org.apache.ibatis.plugin.Intercepts;
+import org.apache.ibatis.plugin.Invocation;
+import org.apache.ibatis.plugin.Signature;
+import org.apache.ibatis.session.ResultHandler;
+
+import java.sql.Statement;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Intercepts({
+ @Signature(type = StatementHandler.class, method = "batch", args = {Statement.class}),
+ @Signature(type = StatementHandler.class, method = "update", args = {Statement.class}),
+ @Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),
+ @Signature(type = StatementHandler.class, method = "queryCursor", args = {Statement.class}),
+})
+public class ExecutingSQLInterceptor implements Interceptor {
+
+ private final static Map thread2ExecutingSQLMap = new ConcurrentHashMap<>();
+
+ public static Map getThread2ExecutingSQLMap() {
+ return new HashMap<>(thread2ExecutingSQLMap);
+ }
+
+ public static void clearThread2ExecutingSQLMap() {
+ thread2ExecutingSQLMap.clear();
+ }
+
+ @Override
+ public Object intercept(Invocation invocation) throws Throwable {
+ try {
+ InterceptorContext interceptorContext = InterceptorContext.get();
+ if (interceptorContext != null) {
+ MappedStatement mappedStatement = interceptorContext.getMappedStatement();
+ String sqlId = mappedStatement.getId();
+ thread2ExecutingSQLMap.put(Thread.currentThread(), sqlId);
+ }
+ return invocation.proceed();
+ } finally {
+ thread2ExecutingSQLMap.remove(Thread.currentThread());
+ }
+ }
+}
diff --git a/src/main/java/neatlogic/framework/dao/plugin/ModifyResultMapTypeHandlerInterceptor.java b/src/main/java/neatlogic/framework/dao/plugin/ModifyResultMapTypeHandlerInterceptor.java
index c5dd0e73a..e3d955489 100644
--- a/src/main/java/neatlogic/framework/dao/plugin/ModifyResultMapTypeHandlerInterceptor.java
+++ b/src/main/java/neatlogic/framework/dao/plugin/ModifyResultMapTypeHandlerInterceptor.java
@@ -12,6 +12,7 @@
package neatlogic.framework.dao.plugin;
+import neatlogic.framework.asynchronization.threadlocal.InterceptorContext;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.mapping.MappedStatement;
@@ -43,12 +44,15 @@ import java.util.List;
public class ModifyResultMapTypeHandlerInterceptor implements Interceptor {
Logger logger = LoggerFactory.getLogger(ModifyResultMapTypeHandlerInterceptor.class);
- public static final ThreadLocal mappedStatementThreadLocal = new ThreadLocal<>();
@Override
public Object intercept(Invocation invocation) throws Throwable {
try {
- MappedStatement mappedStatement = mappedStatementThreadLocal.get();
+ MappedStatement mappedStatement = null;
+ InterceptorContext interceptorContext = InterceptorContext.get();
+ if (interceptorContext != null) {
+ mappedStatement = interceptorContext.getMappedStatement();
+ }
if (mappedStatement != null) {
Configuration configuration = mappedStatement.getConfiguration();
int resultMappingSize = 0;
@@ -79,8 +83,6 @@ public class ModifyResultMapTypeHandlerInterceptor implements Interceptor {
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
- } finally {
- mappedStatementThreadLocal.remove();
}
return invocation.proceed();
}
diff --git a/src/main/java/neatlogic/framework/dao/plugin/SqlCostInterceptor.java b/src/main/java/neatlogic/framework/dao/plugin/SqlCostInterceptor.java
index b5793d92a..7cbffc1d5 100644
--- a/src/main/java/neatlogic/framework/dao/plugin/SqlCostInterceptor.java
+++ b/src/main/java/neatlogic/framework/dao/plugin/SqlCostInterceptor.java
@@ -12,6 +12,7 @@
package neatlogic.framework.dao.plugin;
+import neatlogic.framework.asynchronization.threadlocal.InterceptorContext;
import neatlogic.framework.asynchronization.threadlocal.RequestContext;
import neatlogic.framework.asynchronization.threadlocal.TenantContext;
import neatlogic.framework.asynchronization.threadlocal.UserContext;
@@ -48,8 +49,6 @@ import java.util.regex.Matcher;
})
public class SqlCostInterceptor implements Interceptor {
Logger logger = LoggerFactory.getLogger(SqlCostInterceptor.class);
- // 判断是否查询了数据库
- public static final ThreadLocal QUERY_FROM_DATABASE_INSTANCE = new ThreadLocal<>();
public static class SqlIdMap {
private static final Set sqlSet = new HashSet<>();
@@ -101,7 +100,6 @@ public class SqlCostInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
- ModifyResultMapTypeHandlerInterceptor.mappedStatementThreadLocal.set(mappedStatement);
long starttime = 0;
SqlAuditVo sqlAuditVo = null;
boolean hasCacheFirstLevel = false;
@@ -150,43 +148,42 @@ public class SqlCostInterceptor implements Interceptor {
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
- QUERY_FROM_DATABASE_INSTANCE.set(false);
- try {
- // 执行完上面的任务后,不改变原有的sql执行过程
- Object val = invocation.proceed();
- if (sqlAuditVo != null) {
- if (QUERY_FROM_DATABASE_INSTANCE.get()) {
- // sql语句被执行,没有使用到缓存
- sqlAuditVo.setUseCacheLevel(StringUtils.EMPTY);
+ InterceptorContext interceptorContext = InterceptorContext.get();
+ if (interceptorContext != null) {
+ interceptorContext.setQueryFromDatabase(false);
+ }
+ // 执行完上面的任务后,不改变原有的sql执行过程
+ Object val = invocation.proceed();
+ if (sqlAuditVo != null) {
+ if (interceptorContext != null && interceptorContext.getQueryFromDatabase()) {
+ // sql语句被执行,没有使用到缓存
+ sqlAuditVo.setUseCacheLevel(StringUtils.EMPTY);
+ } else {
+ if (hasCacheFirstLevel) {
+ sqlAuditVo.setUseCacheLevel("一级缓存");
} else {
- if (hasCacheFirstLevel) {
- sqlAuditVo.setUseCacheLevel("一级缓存");
- } else {
- sqlAuditVo.setUseCacheLevel("二级缓存");
- }
+ sqlAuditVo.setUseCacheLevel("二级缓存");
}
- sqlAuditVo.setTimeCost(System.currentTimeMillis() - starttime);
- sqlAuditVo.setRunTime(new Date());
+ }
+ sqlAuditVo.setTimeCost(System.currentTimeMillis() - starttime);
+ sqlAuditVo.setRunTime(new Date());
- if (val != null) {
- if (val instanceof List) {
- sqlAuditVo.setRecordCount(((List) val).size());
- } else {
- sqlAuditVo.setRecordCount(1);
- }
- }
- SqlAuditManager.addSqlAudit(sqlAuditVo);
- RequestContext requestContext = RequestContext.get();
- if (requestContext != null) {
- requestContext.addSqlAudit(sqlAuditVo);
+ if (val != null) {
+ if (val instanceof List) {
+ sqlAuditVo.setRecordCount(((List) val).size());
+ } else {
+ sqlAuditVo.setRecordCount(1);
}
- //System.out.println("time cost:" + (System.currentTimeMillis() - starttime) + "ms");
- //System.out.println("###########################################################################");
}
- return val;
- } finally {
- QUERY_FROM_DATABASE_INSTANCE.remove();
+ SqlAuditManager.addSqlAudit(sqlAuditVo);
+ RequestContext requestContext = RequestContext.get();
+ if (requestContext != null) {
+ requestContext.addSqlAudit(sqlAuditVo);
+ }
+ //System.out.println("time cost:" + (System.currentTimeMillis() - starttime) + "ms");
+ //System.out.println("###########################################################################");
}
+ return val;
}
public static String getSql(MappedStatement mappedStatement, Object parameterObject) {
diff --git a/src/main/java/neatlogic/framework/dao/plugin/ThreadLocalInterceptor.java b/src/main/java/neatlogic/framework/dao/plugin/ThreadLocalInterceptor.java
new file mode 100644
index 000000000..badb6933c
--- /dev/null
+++ b/src/main/java/neatlogic/framework/dao/plugin/ThreadLocalInterceptor.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * *
+ * * Copyright (C) 2025 TechSure Co., Ltd. All Rights Reserved.
+ * * This file is part of the NeatLogic software.
+ * * Licensed under the NeatLogic Sustainable Use License (NSUL), Version 4.x – 2025.
+ * * You may use this file only in compliance with the License.
+ * * See the LICENSE file distributed with this work for the full license text.
+ * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * *
+ *
+ */
+
+package neatlogic.framework.dao.plugin;
+
+import neatlogic.framework.asynchronization.threadlocal.InterceptorContext;
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.plugin.Interceptor;
+import org.apache.ibatis.plugin.Intercepts;
+import org.apache.ibatis.plugin.Invocation;
+import org.apache.ibatis.plugin.Signature;
+import org.apache.ibatis.session.ResultHandler;
+import org.apache.ibatis.session.RowBounds;
+
+@Intercepts({
+ @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
+ @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
+})
+public class ThreadLocalInterceptor implements Interceptor {
+
+ @Override
+ public Object intercept(Invocation invocation) throws Throwable {
+ InterceptorContext interceptorContext = InterceptorContext.init();
+ try {
+ interceptorContext.setMappedStatement((MappedStatement) invocation.getArgs()[0]);
+ interceptorContext.setParameter(invocation.getArgs()[1]);
+ return invocation.proceed();
+ } finally {
+ interceptorContext.release();
+ }
+ }
+}
diff --git a/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java b/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
index 0b30fe1c7..fa48dab72 100644
--- a/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
+++ b/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
@@ -14,24 +14,22 @@ package neatlogic.framework.store.mysql;
import com.zaxxer.hikari.HikariDataSource;
import neatlogic.framework.asynchronization.threadlocal.UserContext;
-import neatlogic.framework.common.config.Config;
import neatlogic.framework.common.util.RC4Util;
+import neatlogic.framework.dao.plugin.ExecutingSQLInterceptor;
+import neatlogic.framework.util.ThreadUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.CannotGetJdbcConnectionException;
-import java.lang.management.ManagementFactory;
-import java.lang.management.ThreadInfo;
-import java.lang.management.ThreadMXBean;
+import java.io.IOException;
+import java.io.StringWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLTransientConnectionException;
import java.sql.Statement;
-import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
-import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
public class NeatLogicBasicDataSource extends HikariDataSource {//替换dbcp2的BasicDataSource
@@ -39,65 +37,41 @@ public class NeatLogicBasicDataSource extends HikariDataSource {//替换dbcp2的
// 保存上次查询ShowProcesslist命令的时间毫秒数
private static volatile long lastShowProcesslistMilliseconds = -1;
- // 持有数据库连接的线程Map
- private final static Map holdingConnectionThreadMap = new ConcurrentHashMap<>();
+ private static volatile int count = -1;
- public static void addHoldingConnectionThreadByConnection(Connection connection) {
- int size = holdingConnectionThreadMap.size();
- if (size <= Config.DATASOURCE_MAXIMUN_POOL_SIZE()) {
- holdingConnectionThreadMap.put(connection, Thread.currentThread());
- } else {
- logger.error("持有数据库连接的线程Map大小为{}, 数据库连接池最大数量为{}", size, Config.DATASOURCE_MAXIMUN_POOL_SIZE());
- }
- }
-
- public static Thread removeHoldingConnectionThreadByConnection(Connection connection) {
- return holdingConnectionThreadMap.remove(connection);
- }
-
- public static String getHoldingConnectionThreadStackTrace(Map holdingConnectionThreadMap) {
- ThreadMXBean mxBean = ManagementFactory.getThreadMXBean();
- ThreadInfo[] threadInfos = mxBean.getThreadInfo(mxBean.getAllThreadIds(), 0);
- Map threadInfoMap = new HashMap<>();
- for (ThreadInfo threadInfo : threadInfos) {
- threadInfoMap.put(threadInfo.getThreadId(), threadInfo);
- }
- StringBuilder stringBuilder = new StringBuilder(System.lineSeparator());
- stringBuilder.append("总线程数为: ").append(holdingConnectionThreadMap.size()).append(System.lineSeparator());
- for (Map.Entry entry : holdingConnectionThreadMap.entrySet()) {
- Thread thread = entry.getValue();
- stringBuilder.append("[").append(thread.getName()).append("] prio=").append(thread.getPriority())
- .append(" tid=").append(thread.getId())
- .append(" ").append(thread.getState())
- .append(" ").append(thread.isDaemon() ? "deamon" : "worker");
- ThreadInfo threadInfo = threadInfoMap.get(thread.getId());
- if (threadInfo != null) {
- stringBuilder.append(" native=").append(threadInfo.isInNative())
- .append(", suspended=").append(threadInfo.isSuspended())
- .append(", block=").append(threadInfo.getBlockedCount())
- .append(", wait=").append(threadInfo.getWaitedCount())
- .append(" lock=").append(threadInfo.getLockName())
- .append(" owned by ").append(threadInfo.getLockOwnerName())
- .append(" (").append(threadInfo.getLockOwnerId())
- .append("), cpu=").append(mxBean.getThreadCpuTime(threadInfo.getThreadId()) / 1000000L)
- .append(", user=").append(mxBean.getThreadUserTime(threadInfo.getThreadId()) / 1000000L);
- }
- stringBuilder.append(System.lineSeparator());
- StackTraceElement[] stackTrace = thread.getStackTrace();
- for (StackTraceElement stackTraceElement : stackTrace) {
- stringBuilder.append(" at ").append(stackTraceElement).append(System.lineSeparator());
- }
- }
- return stringBuilder.toString();
- }
-
- private synchronized void audit(Map holdingConnectionThreadMap) {
+ /**
+ * 五分钟内只打印三次日志
+ */
+ private synchronized void audit() {
+ boolean flag = false;
long currentTimeMillis = System.currentTimeMillis();
long interval = currentTimeMillis - lastShowProcesslistMilliseconds;
if (interval > TimeUnit.MINUTES.toMillis(1)) {
- lastShowProcesslistMilliseconds = currentTimeMillis;
- Logger SQLTransientConnectionExceptionAuditLogger = LoggerFactory.getLogger("SQLTransientConnectionExceptionAudit");
- SQLTransientConnectionExceptionAuditLogger.error(getHoldingConnectionThreadStackTrace(holdingConnectionThreadMap));
+ count = 0;
+ flag = true;
+ } else {
+ if (count < 3) {
+ count++;
+ flag = true;
+ }
+ }
+ if (flag) {
+ try {
+ Map thread2ExecutingSQLMap = ExecutingSQLInterceptor.getThread2ExecutingSQLMap();
+ StringWriter writer = new StringWriter();
+ ThreadUtil.dumpTraces(writer);
+ writer.write("=================正在执行的SQL语句有" + thread2ExecutingSQLMap.size() + "条=================");
+ for (Map.Entry entry : thread2ExecutingSQLMap.entrySet()) {
+ Thread thread = entry.getKey();
+ String value = entry.getValue();
+ writer.write("[" + thread.getName() + "] 线程正在执行 " + value);
+ writer.write(System.lineSeparator());
+ }
+ Logger SQLTransientConnectionExceptionAuditLogger = LoggerFactory.getLogger("SQLTransientConnectionExceptionAudit");
+ SQLTransientConnectionExceptionAuditLogger.error(writer.toString());
+ } catch (IOException e) {
+ logger.error(e.getMessage(), e);
+ }
}
}
@@ -106,14 +80,8 @@ public class NeatLogicBasicDataSource extends HikariDataSource {//替换dbcp2的
Connection conn = null;
try {
conn = super.getConnection();
- if (Config.DATASOURCE_CONNECTION_HOLDER_TRACK_ENABLE()) {
- addHoldingConnectionThreadByConnection(conn);
- conn = new NeatLogicConnection(conn);
- }
} catch (CannotGetJdbcConnectionException | SQLTransientConnectionException ex) {
- if (Config.DATASOURCE_CONNECTION_HOLDER_TRACK_ENABLE()) {
- audit(new HashMap<>(holdingConnectionThreadMap));
- }
+ audit();
throw ex;
}
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
diff --git a/src/main/java/neatlogic/framework/store/mysql/NeatLogicConnection.java b/src/main/java/neatlogic/framework/store/mysql/NeatLogicConnection.java
deleted file mode 100644
index 73ce446e4..000000000
--- a/src/main/java/neatlogic/framework/store/mysql/NeatLogicConnection.java
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- *
- * Copyright (C) 2025 TechSure Co., Ltd. All Rights Reserved.
- * This file is part of the NeatLogic software.
- * Licensed under the NeatLogic Sustainable Use License (NSUL), Version 4.x – 2025.
- * You may use this file only in compliance with the License.
- * See the LICENSE file distributed with this work for the full license text.
- * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *
- */
-
-package neatlogic.framework.store.mysql;
-
-import java.sql.*;
-import java.util.Map;
-import java.util.Properties;
-import java.util.concurrent.Executor;
-
-public class NeatLogicConnection implements Connection {
-
- private final Connection connection;
-
- public NeatLogicConnection(Connection connection) {
- this.connection = connection;
- }
-
- @Override
- public Statement createStatement() throws SQLException {
- return this.connection.createStatement();
- }
-
- @Override
- public PreparedStatement prepareStatement(String sql) throws SQLException {
- return this.connection.prepareStatement(sql);
- }
-
- @Override
- public CallableStatement prepareCall(String sql) throws SQLException {
- return this.connection.prepareCall(sql);
- }
-
- @Override
- public String nativeSQL(String sql) throws SQLException {
- return this.connection.nativeSQL(sql);
- }
-
- @Override
- public void setAutoCommit(boolean autoCommit) throws SQLException {
- this.connection.setAutoCommit(autoCommit);
- }
-
- @Override
- public boolean getAutoCommit() throws SQLException {
- return this.connection.getAutoCommit();
- }
-
- @Override
- public void commit() throws SQLException {
- this.connection.commit();
- }
-
- @Override
- public void rollback() throws SQLException {
- this.connection.rollback();
- }
-
- @Override
- public void close() throws SQLException {
- NeatLogicBasicDataSource.removeHoldingConnectionThreadByConnection(this.connection);
- this.connection.close();
- }
-
- @Override
- public boolean isClosed() throws SQLException {
- return this.connection.isClosed();
- }
-
- @Override
- public DatabaseMetaData getMetaData() throws SQLException {
- return this.connection.getMetaData();
- }
-
- @Override
- public void setReadOnly(boolean readOnly) throws SQLException {
- this.connection.setReadOnly(readOnly);
- }
-
- @Override
- public boolean isReadOnly() throws SQLException {
- return this.connection.isReadOnly();
- }
-
- @Override
- public void setCatalog(String catalog) throws SQLException {
- this.connection.setCatalog(catalog);
- }
-
- @Override
- public String getCatalog() throws SQLException {
- return this.connection.getCatalog();
- }
-
- @Override
- public void setTransactionIsolation(int level) throws SQLException {
- this.connection.setTransactionIsolation(level);
- }
-
- @Override
- public int getTransactionIsolation() throws SQLException {
- return this.connection.getTransactionIsolation();
- }
-
- @Override
- public SQLWarning getWarnings() throws SQLException {
- return this.connection.getWarnings();
- }
-
- @Override
- public void clearWarnings() throws SQLException {
- this.connection.clearWarnings();
- }
-
- @Override
- public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
- return this.connection.createStatement(resultSetType, resultSetConcurrency);
- }
-
- @Override
- public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
- return this.connection.prepareStatement(sql, resultSetType, resultSetConcurrency);
- }
-
- @Override
- public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
- return this.connection.prepareCall(sql, resultSetType, resultSetConcurrency);
- }
-
- @Override
- public Map> getTypeMap() throws SQLException {
- return this.connection.getTypeMap();
- }
-
- @Override
- public void setTypeMap(Map> map) throws SQLException {
- this.connection.setTypeMap(map);
- }
-
- @Override
- public void setHoldability(int holdability) throws SQLException {
- this.connection.setHoldability(holdability);
- }
-
- @Override
- public int getHoldability() throws SQLException {
- return this.connection.getHoldability();
- }
-
- @Override
- public Savepoint setSavepoint() throws SQLException {
- return this.connection.setSavepoint();
- }
-
- @Override
- public Savepoint setSavepoint(String name) throws SQLException {
- return this.connection.setSavepoint(name);
- }
-
- @Override
- public void rollback(Savepoint savepoint) throws SQLException {
- this.connection.rollback(savepoint);
- }
-
- @Override
- public void releaseSavepoint(Savepoint savepoint) throws SQLException {
- this.connection.releaseSavepoint(savepoint);
- }
-
-
- @Override
- public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
- return this.connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
- }
-
- @Override
- public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
- return this.connection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
- }
-
- @Override
- public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
- return this.connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
- }
-
- @Override
- public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
- return this.connection.prepareStatement(sql, autoGeneratedKeys);
- }
-
- @Override
- public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
- return this.connection.prepareStatement(sql, columnIndexes);
- }
-
- @Override
- public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
- return this.connection.prepareStatement(sql, columnNames);
- }
-
- @Override
- public Clob createClob() throws SQLException {
- return this.connection.createClob();
- }
-
- @Override
- public Blob createBlob() throws SQLException {
- return this.connection.createBlob();
- }
-
- @Override
- public NClob createNClob() throws SQLException {
- return this.connection.createNClob();
- }
-
- @Override
- public SQLXML createSQLXML() throws SQLException {
- return this.connection.createSQLXML();
- }
-
- @Override
- public boolean isValid(int timeout) throws SQLException {
- return this.connection.isValid(timeout);
- }
-
- @Override
- public void setClientInfo(String name, String value) throws SQLClientInfoException {
- this.connection.setClientInfo(name, value);
- }
-
- @Override
- public void setClientInfo(Properties properties) throws SQLClientInfoException {
- this.connection.setClientInfo(properties);
- }
-
- @Override
- public String getClientInfo(String name) throws SQLException {
- return this.connection.getClientInfo(name);
- }
-
- @Override
- public Properties getClientInfo() throws SQLException {
- return this.connection.getClientInfo();
- }
-
- @Override
- public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
- return this.connection.createArrayOf(typeName, elements);
- }
-
- @Override
- public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
- return this.connection.createStruct(typeName, attributes);
- }
-
- @Override
- public void setSchema(String schema) throws SQLException {
- this.connection.setSchema(schema);
- }
-
- @Override
- public String getSchema() throws SQLException {
- return this.connection.getSchema();
- }
-
- @Override
- public void abort(Executor executor) throws SQLException {
- this.connection.abort(executor);
- }
-
- @Override
- public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
- this.connection.setNetworkTimeout(executor, milliseconds);
- }
-
- @Override
- public int getNetworkTimeout() throws SQLException {
- return this.connection.getNetworkTimeout();
- }
-
- @Override
- public void beginRequest() throws SQLException {
- this.connection.beginRequest();
- }
-
- @Override
- public void endRequest() throws SQLException {
- this.connection.endRequest();
- }
-
- @Override
- public boolean setShardingKeyIfValid(ShardingKey shardingKey, ShardingKey superShardingKey, int timeout) throws SQLException {
- return this.connection.setShardingKeyIfValid(shardingKey, superShardingKey, timeout);
- }
-
- @Override
- public boolean setShardingKeyIfValid(ShardingKey shardingKey, int timeout) throws SQLException {
- return this.connection.setShardingKeyIfValid(shardingKey, timeout);
- }
-
- @Override
- public void setShardingKey(ShardingKey shardingKey, ShardingKey superShardingKey) throws SQLException {
- this.connection.setShardingKey(shardingKey, superShardingKey);
- }
-
- @Override
- public void setShardingKey(ShardingKey shardingKey) throws SQLException {
- this.connection.setShardingKey(shardingKey);
- }
-
- @Override
- public T unwrap(Class iface) throws SQLException {
- return this.connection.unwrap(iface);
- }
-
- @Override
- public boolean isWrapperFor(Class> iface) throws SQLException {
- return this.connection.isWrapperFor(iface);
- }
-}
diff --git a/src/main/java/neatlogic/framework/util/ThreadUtil.java b/src/main/java/neatlogic/framework/util/ThreadUtil.java
new file mode 100644
index 000000000..9d86b1086
--- /dev/null
+++ b/src/main/java/neatlogic/framework/util/ThreadUtil.java
@@ -0,0 +1,59 @@
+/*
+ *
+ * *
+ * * Copyright (C) 2025 TechSure Co., Ltd. All Rights Reserved.
+ * * This file is part of the NeatLogic software.
+ * * Licensed under the NeatLogic Sustainable Use License (NSUL), Version 4.x – 2025.
+ * * You may use this file only in compliance with the License.
+ * * See the LICENSE file distributed with this work for the full license text.
+ * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * *
+ *
+ */
+
+package neatlogic.framework.util;
+
+import neatlogic.framework.asynchronization.threadlocal.RequestContext;
+import neatlogic.framework.common.config.Config;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ThreadUtil {
+
+ public static void dumpTraces(Writer writer) throws IOException {
+ ThreadMXBean mxBean = ManagementFactory.getThreadMXBean();
+ ThreadInfo[] threadInfos = mxBean.getThreadInfo(mxBean.getAllThreadIds(), 0);
+ Map threadInfoMap = new HashMap<>();
+ for (ThreadInfo threadInfo : threadInfos) {
+ threadInfoMap.put(threadInfo.getThreadId(), threadInfo);
+ }
+ Map stacks = Thread.getAllStackTraces();
+ long now = System.currentTimeMillis();
+ writer.write("=================" + stacks.size() + " thread of " + RequestContext.get().getRequest().getLocalAddr() + " at " + new SimpleDateFormat("yyyy/MM/dd HH:mm:ss z").format(new Date(now)) + " start.serverId is " + Config.SCHEDULE_SERVER_ID + "=================\n\n");
+ for (Map.Entry entry : stacks.entrySet()) {
+ Thread thread = entry.getKey();
+ writer.write("\"" + thread.getName() + "\" prio=" + thread.getPriority() + " tid=" + thread.getId() + " " + thread.getState() + " " + (thread.isDaemon() ? "deamon" : "worker"));
+ ThreadInfo threadInfo = threadInfoMap.get(thread.getId());
+ if (threadInfo != null) {
+ writer.write(" native=" + threadInfo.isInNative() + ", suspended=" + threadInfo.isSuspended() + ", block=" + threadInfo.getBlockedCount() + ", wait=" + threadInfo.getWaitedCount());
+ writer.write(" lock=" + threadInfo.getLockName() + " owned by " + threadInfo.getLockOwnerName() + " (" + threadInfo.getLockOwnerId() + "), cpu=" + (mxBean.getThreadCpuTime(threadInfo.getThreadId()) / 1000000L) + ", user=" + (mxBean.getThreadUserTime(threadInfo.getThreadId()) / 1000000L) + "\n");
+ }
+ for (StackTraceElement element : entry.getValue()) {
+ writer.write("\t\t");
+ writer.write(element.toString());
+ writer.write("\n");
+ }
+ writer.write("\n");
+ }
+ writer.write("=================" + stacks.size() + " thread of " + RequestContext.get().getUrl() + " at " + new SimpleDateFormat("yyyy/MM/dd HH:mm:ss z").format(new Date(now)) + " end.=================\n\n");
+ }
+}
--
Gitee
From 4b6ca71fb1f0adb6945f42258b04be03148c02fe Mon Sep 17 00:00:00 2001
From: "1437892690@qq.com" <1437892690@qq.com>
Date: Mon, 17 Nov 2025 18:35:46 +0800
Subject: [PATCH 04/18] =?UTF-8?q?[=E5=8A=9F=E8=83=BD]=20=E6=95=B0=E6=8D=AE?=
=?UTF-8?q?=E5=BA=93=E8=BF=9E=E6=8E=A5=E6=B1=A0=E8=8E=B7=E5=8F=96=E4=B8=8D?=
=?UTF-8?q?=E5=88=B0=E8=BF=9E=E6=8E=A5=E6=97=B6=E8=AE=B0=E5=BD=95=E7=BA=BF?=
=?UTF-8?q?=E7=A8=8B=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
关联 #[1551594485678080]数据库连接池获取不到连接时记录线程信息 http://192.168.0.96:8090/demo/rdm.html#/story-detail/939050947543040/939050947543042/1551594485678080
---
.../threadlocal/InterceptorContext.java | 16 +++++++---------
.../framework/dao/config/mybatis-config.xml | 1 +
.../dao/plugin/ExecutingSQLInterceptor.java | 16 +++++++---------
.../dao/plugin/ThreadLocalInterceptor.java | 16 +++++++---------
.../neatlogic/framework/util/ThreadUtil.java | 16 +++++++---------
5 files changed, 29 insertions(+), 36 deletions(-)
diff --git a/src/main/java/neatlogic/framework/asynchronization/threadlocal/InterceptorContext.java b/src/main/java/neatlogic/framework/asynchronization/threadlocal/InterceptorContext.java
index 304b4993e..ab8bb9df8 100644
--- a/src/main/java/neatlogic/framework/asynchronization/threadlocal/InterceptorContext.java
+++ b/src/main/java/neatlogic/framework/asynchronization/threadlocal/InterceptorContext.java
@@ -1,14 +1,12 @@
/*
*
- * *
- * * Copyright (C) 2025 TechSure Co., Ltd. All Rights Reserved.
- * * This file is part of the NeatLogic software.
- * * Licensed under the NeatLogic Sustainable Use License (NSUL), Version 4.x – 2025.
- * * You may use this file only in compliance with the License.
- * * See the LICENSE file distributed with this work for the full license text.
- * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
- * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * *
+ * Copyright (C) 2025 TechSure Co., Ltd. All Rights Reserved.
+ * This file is part of the NeatLogic software.
+ * Licensed under the NeatLogic Sustainable Use License (NSUL), Version 4.x – 2025.
+ * You may use this file only in compliance with the License.
+ * See the LICENSE file distributed with this work for the full license text.
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
diff --git a/src/main/java/neatlogic/framework/dao/config/mybatis-config.xml b/src/main/java/neatlogic/framework/dao/config/mybatis-config.xml
index aec63c08b..72b4eca64 100644
--- a/src/main/java/neatlogic/framework/dao/config/mybatis-config.xml
+++ b/src/main/java/neatlogic/framework/dao/config/mybatis-config.xml
@@ -41,6 +41,7 @@ along with this program. If not, see .-->
+
diff --git a/src/main/java/neatlogic/framework/dao/plugin/ExecutingSQLInterceptor.java b/src/main/java/neatlogic/framework/dao/plugin/ExecutingSQLInterceptor.java
index a0d117595..2162017ca 100644
--- a/src/main/java/neatlogic/framework/dao/plugin/ExecutingSQLInterceptor.java
+++ b/src/main/java/neatlogic/framework/dao/plugin/ExecutingSQLInterceptor.java
@@ -1,14 +1,12 @@
/*
*
- * *
- * * Copyright (C) 2025 TechSure Co., Ltd. All Rights Reserved.
- * * This file is part of the NeatLogic software.
- * * Licensed under the NeatLogic Sustainable Use License (NSUL), Version 4.x – 2025.
- * * You may use this file only in compliance with the License.
- * * See the LICENSE file distributed with this work for the full license text.
- * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
- * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * *
+ * Copyright (C) 2025 TechSure Co., Ltd. All Rights Reserved.
+ * This file is part of the NeatLogic software.
+ * Licensed under the NeatLogic Sustainable Use License (NSUL), Version 4.x – 2025.
+ * You may use this file only in compliance with the License.
+ * See the LICENSE file distributed with this work for the full license text.
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
diff --git a/src/main/java/neatlogic/framework/dao/plugin/ThreadLocalInterceptor.java b/src/main/java/neatlogic/framework/dao/plugin/ThreadLocalInterceptor.java
index badb6933c..eae532ea4 100644
--- a/src/main/java/neatlogic/framework/dao/plugin/ThreadLocalInterceptor.java
+++ b/src/main/java/neatlogic/framework/dao/plugin/ThreadLocalInterceptor.java
@@ -1,14 +1,12 @@
/*
*
- * *
- * * Copyright (C) 2025 TechSure Co., Ltd. All Rights Reserved.
- * * This file is part of the NeatLogic software.
- * * Licensed under the NeatLogic Sustainable Use License (NSUL), Version 4.x – 2025.
- * * You may use this file only in compliance with the License.
- * * See the LICENSE file distributed with this work for the full license text.
- * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
- * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * *
+ * Copyright (C) 2025 TechSure Co., Ltd. All Rights Reserved.
+ * This file is part of the NeatLogic software.
+ * Licensed under the NeatLogic Sustainable Use License (NSUL), Version 4.x – 2025.
+ * You may use this file only in compliance with the License.
+ * See the LICENSE file distributed with this work for the full license text.
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
diff --git a/src/main/java/neatlogic/framework/util/ThreadUtil.java b/src/main/java/neatlogic/framework/util/ThreadUtil.java
index 9d86b1086..9203b81d1 100644
--- a/src/main/java/neatlogic/framework/util/ThreadUtil.java
+++ b/src/main/java/neatlogic/framework/util/ThreadUtil.java
@@ -1,14 +1,12 @@
/*
*
- * *
- * * Copyright (C) 2025 TechSure Co., Ltd. All Rights Reserved.
- * * This file is part of the NeatLogic software.
- * * Licensed under the NeatLogic Sustainable Use License (NSUL), Version 4.x – 2025.
- * * You may use this file only in compliance with the License.
- * * See the LICENSE file distributed with this work for the full license text.
- * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
- * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * *
+ * Copyright (C) 2025 TechSure Co., Ltd. All Rights Reserved.
+ * This file is part of the NeatLogic software.
+ * Licensed under the NeatLogic Sustainable Use License (NSUL), Version 4.x – 2025.
+ * You may use this file only in compliance with the License.
+ * See the LICENSE file distributed with this work for the full license text.
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
--
Gitee
From 3b48b515eb6b19dd5ddb4af606b065bca7770f6a Mon Sep 17 00:00:00 2001
From: "1437892690@qq.com" <1437892690@qq.com>
Date: Mon, 17 Nov 2025 18:48:51 +0800
Subject: [PATCH 05/18] =?UTF-8?q?[=E5=8A=9F=E8=83=BD]=20=E6=95=B0=E6=8D=AE?=
=?UTF-8?q?=E5=BA=93=E8=BF=9E=E6=8E=A5=E6=B1=A0=E8=8E=B7=E5=8F=96=E4=B8=8D?=
=?UTF-8?q?=E5=88=B0=E8=BF=9E=E6=8E=A5=E6=97=B6=E8=AE=B0=E5=BD=95=E7=BA=BF?=
=?UTF-8?q?=E7=A8=8B=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
关联 #[1551594485678080]数据库连接池获取不到连接时记录线程信息 http://192.168.0.96:8090/demo/rdm.html#/story-detail/939050947543040/939050947543042/1551594485678080
---
.../java/neatlogic/framework/util/ThreadUtil.java | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/src/main/java/neatlogic/framework/util/ThreadUtil.java b/src/main/java/neatlogic/framework/util/ThreadUtil.java
index 9203b81d1..60b3be730 100644
--- a/src/main/java/neatlogic/framework/util/ThreadUtil.java
+++ b/src/main/java/neatlogic/framework/util/ThreadUtil.java
@@ -14,6 +14,7 @@ package neatlogic.framework.util;
import neatlogic.framework.asynchronization.threadlocal.RequestContext;
import neatlogic.framework.common.config.Config;
+import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.io.Writer;
@@ -36,7 +37,14 @@ public class ThreadUtil {
}
Map stacks = Thread.getAllStackTraces();
long now = System.currentTimeMillis();
- writer.write("=================" + stacks.size() + " thread of " + RequestContext.get().getRequest().getLocalAddr() + " at " + new SimpleDateFormat("yyyy/MM/dd HH:mm:ss z").format(new Date(now)) + " start.serverId is " + Config.SCHEDULE_SERVER_ID + "=================\n\n");
+ String localAddr = StringUtils.EMPTY;
+ String url = StringUtils.EMPTY;
+ RequestContext requestContext = RequestContext.get();
+ if (requestContext != null) {
+ localAddr = requestContext.getRequest().getLocalAddr();
+ url = requestContext.getUrl();
+ }
+ writer.write("\n=================" + stacks.size() + " thread of " + localAddr + " at " + new SimpleDateFormat("yyyy/MM/dd HH:mm:ss z").format(new Date(now)) + " start.serverId is " + Config.SCHEDULE_SERVER_ID + "=================\n\n");
for (Map.Entry entry : stacks.entrySet()) {
Thread thread = entry.getKey();
writer.write("\"" + thread.getName() + "\" prio=" + thread.getPriority() + " tid=" + thread.getId() + " " + thread.getState() + " " + (thread.isDaemon() ? "deamon" : "worker"));
@@ -52,6 +60,6 @@ public class ThreadUtil {
}
writer.write("\n");
}
- writer.write("=================" + stacks.size() + " thread of " + RequestContext.get().getUrl() + " at " + new SimpleDateFormat("yyyy/MM/dd HH:mm:ss z").format(new Date(now)) + " end.=================\n\n");
+ writer.write("=================" + stacks.size() + " thread of " + url + " at " + new SimpleDateFormat("yyyy/MM/dd HH:mm:ss z").format(new Date(now)) + " end.=================\n\n");
}
}
--
Gitee
From 45b3d181164ce24b31be28d5f5d9ebb261f3598c Mon Sep 17 00:00:00 2001
From: "1437892690@qq.com" <1437892690@qq.com>
Date: Mon, 17 Nov 2025 18:54:56 +0800
Subject: [PATCH 06/18] =?UTF-8?q?[=E5=8A=9F=E8=83=BD]=20=E6=95=B0=E6=8D=AE?=
=?UTF-8?q?=E5=BA=93=E8=BF=9E=E6=8E=A5=E6=B1=A0=E8=8E=B7=E5=8F=96=E4=B8=8D?=
=?UTF-8?q?=E5=88=B0=E8=BF=9E=E6=8E=A5=E6=97=B6=E8=AE=B0=E5=BD=95=E7=BA=BF?=
=?UTF-8?q?=E7=A8=8B=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
关联 #[1551594485678080]数据库连接池获取不到连接时记录线程信息 http://192.168.0.96:8090/demo/rdm.html#/story-detail/939050947543040/939050947543042/1551594485678080
---
.../framework/store/mysql/NeatLogicBasicDataSource.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java b/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
index fa48dab72..697861ad8 100644
--- a/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
+++ b/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
@@ -46,7 +46,7 @@ public class NeatLogicBasicDataSource extends HikariDataSource {//替换dbcp2的
boolean flag = false;
long currentTimeMillis = System.currentTimeMillis();
long interval = currentTimeMillis - lastShowProcesslistMilliseconds;
- if (interval > TimeUnit.MINUTES.toMillis(1)) {
+ if (interval > TimeUnit.MINUTES.toMillis(5)) {
count = 0;
flag = true;
} else {
--
Gitee
From f17773dc1c7df7c76e8d7e7f0dfef6d4a9960984 Mon Sep 17 00:00:00 2001
From: "1437892690@qq.com" <1437892690@qq.com>
Date: Mon, 17 Nov 2025 19:04:49 +0800
Subject: [PATCH 07/18] =?UTF-8?q?[=E5=8A=9F=E8=83=BD]=20=E6=95=B0=E6=8D=AE?=
=?UTF-8?q?=E5=BA=93=E8=BF=9E=E6=8E=A5=E6=B1=A0=E8=8E=B7=E5=8F=96=E4=B8=8D?=
=?UTF-8?q?=E5=88=B0=E8=BF=9E=E6=8E=A5=E6=97=B6=E8=AE=B0=E5=BD=95=E7=BA=BF?=
=?UTF-8?q?=E7=A8=8B=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
关联 #[1551594485678080]数据库连接池获取不到连接时记录线程信息 http://192.168.0.96:8090/demo/rdm.html#/story-detail/939050947543040/939050947543042/1551594485678080
---
.../framework/store/mysql/NeatLogicBasicDataSource.java | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java b/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
index 697861ad8..4f5167e90 100644
--- a/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
+++ b/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
@@ -37,7 +37,7 @@ public class NeatLogicBasicDataSource extends HikariDataSource {//替换dbcp2的
// 保存上次查询ShowProcesslist命令的时间毫秒数
private static volatile long lastShowProcesslistMilliseconds = -1;
- private static volatile int count = -1;
+ private static volatile int count = 0;
/**
* 五分钟内只打印三次日志
@@ -47,7 +47,8 @@ public class NeatLogicBasicDataSource extends HikariDataSource {//替换dbcp2的
long currentTimeMillis = System.currentTimeMillis();
long interval = currentTimeMillis - lastShowProcesslistMilliseconds;
if (interval > TimeUnit.MINUTES.toMillis(5)) {
- count = 0;
+ lastShowProcesslistMilliseconds = currentTimeMillis;
+ count = 1;
flag = true;
} else {
if (count < 3) {
--
Gitee
From 41de6d96f630377e6094325b6201430100b2cb98 Mon Sep 17 00:00:00 2001
From: "1437892690@qq.com" <1437892690@qq.com>
Date: Mon, 17 Nov 2025 19:06:37 +0800
Subject: [PATCH 08/18] =?UTF-8?q?[=E5=8A=9F=E8=83=BD]=20=E6=95=B0=E6=8D=AE?=
=?UTF-8?q?=E5=BA=93=E8=BF=9E=E6=8E=A5=E6=B1=A0=E8=8E=B7=E5=8F=96=E4=B8=8D?=
=?UTF-8?q?=E5=88=B0=E8=BF=9E=E6=8E=A5=E6=97=B6=E8=AE=B0=E5=BD=95=E7=BA=BF?=
=?UTF-8?q?=E7=A8=8B=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
关联 #[1551594485678080]数据库连接池获取不到连接时记录线程信息 http://192.168.0.96:8090/demo/rdm.html#/story-detail/939050947543040/939050947543042/1551594485678080
---
.../framework/store/mysql/NeatLogicBasicDataSource.java | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java b/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
index 4f5167e90..402664ccd 100644
--- a/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
+++ b/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
@@ -35,8 +35,8 @@ import java.util.concurrent.TimeUnit;
public class NeatLogicBasicDataSource extends HikariDataSource {//替换dbcp2的BasicDataSource
private static final Logger logger = LoggerFactory.getLogger(NeatLogicBasicDataSource.class);
- // 保存上次查询ShowProcesslist命令的时间毫秒数
- private static volatile long lastShowProcesslistMilliseconds = -1;
+ // 保存上次输出日志的时间毫秒数
+ private static volatile long lastAuditMilliseconds = -1;
private static volatile int count = 0;
/**
@@ -45,9 +45,9 @@ public class NeatLogicBasicDataSource extends HikariDataSource {//替换dbcp2的
private synchronized void audit() {
boolean flag = false;
long currentTimeMillis = System.currentTimeMillis();
- long interval = currentTimeMillis - lastShowProcesslistMilliseconds;
+ long interval = currentTimeMillis - lastAuditMilliseconds;
if (interval > TimeUnit.MINUTES.toMillis(5)) {
- lastShowProcesslistMilliseconds = currentTimeMillis;
+ lastAuditMilliseconds = currentTimeMillis;
count = 1;
flag = true;
} else {
--
Gitee
From b04d43f79dacb57e705d3965c8e7b52f822a46be Mon Sep 17 00:00:00 2001
From: "1437892690@qq.com" <1437892690@qq.com>
Date: Tue, 18 Nov 2025 08:42:06 +0800
Subject: [PATCH 09/18] =?UTF-8?q?[=E5=8A=9F=E8=83=BD]=20=E6=95=B0=E6=8D=AE?=
=?UTF-8?q?=E5=BA=93=E8=BF=9E=E6=8E=A5=E6=B1=A0=E8=8E=B7=E5=8F=96=E4=B8=8D?=
=?UTF-8?q?=E5=88=B0=E8=BF=9E=E6=8E=A5=E6=97=B6=E8=AE=B0=E5=BD=95=E7=BA=BF?=
=?UTF-8?q?=E7=A8=8B=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
关联 #[1551594485678080]数据库连接池获取不到连接时记录线程信息 http://192.168.0.96:8090/demo/rdm.html#/story-detail/939050947543040/939050947543042/1551594485678080
---
src/main/java/neatlogic/framework/util/ThreadUtil.java | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/main/java/neatlogic/framework/util/ThreadUtil.java b/src/main/java/neatlogic/framework/util/ThreadUtil.java
index 60b3be730..d606603d7 100644
--- a/src/main/java/neatlogic/framework/util/ThreadUtil.java
+++ b/src/main/java/neatlogic/framework/util/ThreadUtil.java
@@ -41,8 +41,12 @@ public class ThreadUtil {
String url = StringUtils.EMPTY;
RequestContext requestContext = RequestContext.get();
if (requestContext != null) {
- localAddr = requestContext.getRequest().getLocalAddr();
- url = requestContext.getUrl();
+ if (requestContext.getRequest() != null && StringUtils.isNotBlank(requestContext.getRequest().getLocalAddr())) {
+ localAddr = requestContext.getRequest().getLocalAddr();
+ }
+ if (StringUtils.isNotBlank(requestContext.getUrl())) {
+ url = requestContext.getUrl();
+ }
}
writer.write("\n=================" + stacks.size() + " thread of " + localAddr + " at " + new SimpleDateFormat("yyyy/MM/dd HH:mm:ss z").format(new Date(now)) + " start.serverId is " + Config.SCHEDULE_SERVER_ID + "=================\n\n");
for (Map.Entry entry : stacks.entrySet()) {
--
Gitee
From 49df6a3da8deed2cb27d2ec302e37dd16f147017 Mon Sep 17 00:00:00 2001
From: "1437892690@qq.com" <1437892690@qq.com>
Date: Tue, 18 Nov 2025 11:00:02 +0800
Subject: [PATCH 10/18] =?UTF-8?q?[=E5=8A=9F=E8=83=BD]=20=E6=95=B0=E6=8D=AE?=
=?UTF-8?q?=E5=BA=93=E8=BF=9E=E6=8E=A5=E6=B1=A0=E8=8E=B7=E5=8F=96=E4=B8=8D?=
=?UTF-8?q?=E5=88=B0=E8=BF=9E=E6=8E=A5=E6=97=B6=E8=AE=B0=E5=BD=95=E7=BA=BF?=
=?UTF-8?q?=E7=A8=8B=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
关联 #[1551594485678080]数据库连接池获取不到连接时记录线程信息 http://192.168.0.96:8090/demo/rdm.html#/story-detail/939050947543040/939050947543042/1551594485678080
---
.../framework/store/mysql/NeatLogicBasicDataSource.java | 1 +
src/main/java/neatlogic/framework/util/ThreadUtil.java | 4 +++-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java b/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
index 402664ccd..e6606c9e8 100644
--- a/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
+++ b/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
@@ -62,6 +62,7 @@ public class NeatLogicBasicDataSource extends HikariDataSource {//替换dbcp2的
StringWriter writer = new StringWriter();
ThreadUtil.dumpTraces(writer);
writer.write("=================正在执行的SQL语句有" + thread2ExecutingSQLMap.size() + "条=================");
+ writer.write(System.lineSeparator());
for (Map.Entry entry : thread2ExecutingSQLMap.entrySet()) {
Thread thread = entry.getKey();
String value = entry.getValue();
diff --git a/src/main/java/neatlogic/framework/util/ThreadUtil.java b/src/main/java/neatlogic/framework/util/ThreadUtil.java
index d606603d7..7e4651bae 100644
--- a/src/main/java/neatlogic/framework/util/ThreadUtil.java
+++ b/src/main/java/neatlogic/framework/util/ThreadUtil.java
@@ -33,7 +33,9 @@ public class ThreadUtil {
ThreadInfo[] threadInfos = mxBean.getThreadInfo(mxBean.getAllThreadIds(), 0);
Map threadInfoMap = new HashMap<>();
for (ThreadInfo threadInfo : threadInfos) {
- threadInfoMap.put(threadInfo.getThreadId(), threadInfo);
+ if (threadInfo != null) {
+ threadInfoMap.put(threadInfo.getThreadId(), threadInfo);
+ }
}
Map stacks = Thread.getAllStackTraces();
long now = System.currentTimeMillis();
--
Gitee
From bfd5a6339b512611d440d756e4fb1948ad4b4f58 Mon Sep 17 00:00:00 2001
From: "1437892690@qq.com" <1437892690@qq.com>
Date: Tue, 18 Nov 2025 11:16:42 +0800
Subject: [PATCH 11/18] =?UTF-8?q?[=E5=8A=9F=E8=83=BD]=20=E6=95=B0=E6=8D=AE?=
=?UTF-8?q?=E5=BA=93=E8=BF=9E=E6=8E=A5=E6=B1=A0=E8=8E=B7=E5=8F=96=E4=B8=8D?=
=?UTF-8?q?=E5=88=B0=E8=BF=9E=E6=8E=A5=E6=97=B6=E8=AE=B0=E5=BD=95=E7=BA=BF?=
=?UTF-8?q?=E7=A8=8B=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
关联 #[1551594485678080]数据库连接池获取不到连接时记录线程信息 http://192.168.0.96:8090/demo/rdm.html#/story-detail/939050947543040/939050947543042/1551594485678080
---
.../framework/dao/plugin/ExecutingSQLInterceptor.java | 8 ++++----
.../framework/store/mysql/NeatLogicBasicDataSource.java | 8 ++++----
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/main/java/neatlogic/framework/dao/plugin/ExecutingSQLInterceptor.java b/src/main/java/neatlogic/framework/dao/plugin/ExecutingSQLInterceptor.java
index 2162017ca..f01211b4c 100644
--- a/src/main/java/neatlogic/framework/dao/plugin/ExecutingSQLInterceptor.java
+++ b/src/main/java/neatlogic/framework/dao/plugin/ExecutingSQLInterceptor.java
@@ -34,9 +34,9 @@ import java.util.concurrent.ConcurrentHashMap;
})
public class ExecutingSQLInterceptor implements Interceptor {
- private final static Map thread2ExecutingSQLMap = new ConcurrentHashMap<>();
+ private final static Map thread2ExecutingSQLMap = new ConcurrentHashMap<>();
- public static Map getThread2ExecutingSQLMap() {
+ public static Map getThread2ExecutingSQLMap() {
return new HashMap<>(thread2ExecutingSQLMap);
}
@@ -51,11 +51,11 @@ public class ExecutingSQLInterceptor implements Interceptor {
if (interceptorContext != null) {
MappedStatement mappedStatement = interceptorContext.getMappedStatement();
String sqlId = mappedStatement.getId();
- thread2ExecutingSQLMap.put(Thread.currentThread(), sqlId);
+ thread2ExecutingSQLMap.put(Thread.currentThread().getName(), sqlId);
}
return invocation.proceed();
} finally {
- thread2ExecutingSQLMap.remove(Thread.currentThread());
+ thread2ExecutingSQLMap.remove(Thread.currentThread().getName());
}
}
}
diff --git a/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java b/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
index e6606c9e8..9f507dd78 100644
--- a/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
+++ b/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
@@ -58,15 +58,15 @@ public class NeatLogicBasicDataSource extends HikariDataSource {//替换dbcp2的
}
if (flag) {
try {
- Map thread2ExecutingSQLMap = ExecutingSQLInterceptor.getThread2ExecutingSQLMap();
+ Map thread2ExecutingSQLMap = ExecutingSQLInterceptor.getThread2ExecutingSQLMap();
StringWriter writer = new StringWriter();
ThreadUtil.dumpTraces(writer);
writer.write("=================正在执行的SQL语句有" + thread2ExecutingSQLMap.size() + "条=================");
writer.write(System.lineSeparator());
- for (Map.Entry entry : thread2ExecutingSQLMap.entrySet()) {
- Thread thread = entry.getKey();
+ for (Map.Entry entry : thread2ExecutingSQLMap.entrySet()) {
+ String key = entry.getKey();
String value = entry.getValue();
- writer.write("[" + thread.getName() + "] 线程正在执行 " + value);
+ writer.write("[" + key + "] 线程正在执行 " + value);
writer.write(System.lineSeparator());
}
Logger SQLTransientConnectionExceptionAuditLogger = LoggerFactory.getLogger("SQLTransientConnectionExceptionAudit");
--
Gitee
From 9ab80f74bdc636c3f7971150af01b89e66ac70a7 Mon Sep 17 00:00:00 2001
From: "1437892690@qq.com" <1437892690@qq.com>
Date: Tue, 18 Nov 2025 12:01:35 +0800
Subject: [PATCH 12/18] =?UTF-8?q?[=E5=8A=9F=E8=83=BD]=20=E6=95=B0=E6=8D=AE?=
=?UTF-8?q?=E5=BA=93=E8=BF=9E=E6=8E=A5=E6=B1=A0=E8=8E=B7=E5=8F=96=E4=B8=8D?=
=?UTF-8?q?=E5=88=B0=E8=BF=9E=E6=8E=A5=E6=97=B6=E8=AE=B0=E5=BD=95=E7=BA=BF?=
=?UTF-8?q?=E7=A8=8B=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
关联 #[1551594485678080]数据库连接池获取不到连接时记录线程信息 http://192.168.0.96:8090/demo/rdm.html#/story-detail/939050947543040/939050947543042/1551594485678080
---
.../store/mysql/NeatLogicBasicDataSource.java | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java b/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
index 9f507dd78..807921288 100644
--- a/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
+++ b/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
@@ -12,10 +12,13 @@
package neatlogic.framework.store.mysql;
+import com.alibaba.fastjson.JSON;
import com.zaxxer.hikari.HikariDataSource;
+import com.zaxxer.hikari.HikariPoolMXBean;
import neatlogic.framework.asynchronization.threadlocal.UserContext;
import neatlogic.framework.common.util.RC4Util;
import neatlogic.framework.dao.plugin.ExecutingSQLInterceptor;
+import neatlogic.framework.dto.healthcheck.DataSourceInfoVo;
import neatlogic.framework.util.ThreadUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
@@ -42,7 +45,7 @@ public class NeatLogicBasicDataSource extends HikariDataSource {//替换dbcp2的
/**
* 五分钟内只打印三次日志
*/
- private synchronized void audit() {
+ private synchronized void audit(DataSourceInfoVo dataSourceInfoVo, Map thread2ExecutingSQLMap) {
boolean flag = false;
long currentTimeMillis = System.currentTimeMillis();
long interval = currentTimeMillis - lastAuditMilliseconds;
@@ -58,7 +61,6 @@ public class NeatLogicBasicDataSource extends HikariDataSource {//替换dbcp2的
}
if (flag) {
try {
- Map thread2ExecutingSQLMap = ExecutingSQLInterceptor.getThread2ExecutingSQLMap();
StringWriter writer = new StringWriter();
ThreadUtil.dumpTraces(writer);
writer.write("=================正在执行的SQL语句有" + thread2ExecutingSQLMap.size() + "条=================");
@@ -69,6 +71,7 @@ public class NeatLogicBasicDataSource extends HikariDataSource {//替换dbcp2的
writer.write("[" + key + "] 线程正在执行 " + value);
writer.write(System.lineSeparator());
}
+ writer.write("连接池信息: " + JSON.toJSONString(dataSourceInfoVo));
Logger SQLTransientConnectionExceptionAuditLogger = LoggerFactory.getLogger("SQLTransientConnectionExceptionAudit");
SQLTransientConnectionExceptionAuditLogger.error(writer.toString());
} catch (IOException e) {
@@ -83,7 +86,17 @@ public class NeatLogicBasicDataSource extends HikariDataSource {//替换dbcp2的
try {
conn = super.getConnection();
} catch (CannotGetJdbcConnectionException | SQLTransientConnectionException ex) {
- audit();
+ DataSourceInfoVo dataSourceInfoVo = new DataSourceInfoVo();
+ dataSourceInfoVo.setPoolName(this.getPoolName());
+ HikariPoolMXBean hikariPoolMXBean = this.getHikariPoolMXBean();
+ if (hikariPoolMXBean != null) {
+ dataSourceInfoVo.setIdleConnections(hikariPoolMXBean.getIdleConnections());
+ dataSourceInfoVo.setActiveConnections(hikariPoolMXBean.getActiveConnections());
+ dataSourceInfoVo.setThreadsAwaitingConnection(hikariPoolMXBean.getThreadsAwaitingConnection());
+ dataSourceInfoVo.setTotalConnections(hikariPoolMXBean.getTotalConnections());
+ }
+ Map thread2ExecutingSQLMap = ExecutingSQLInterceptor.getThread2ExecutingSQLMap();
+ audit(dataSourceInfoVo, thread2ExecutingSQLMap);
throw ex;
}
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
--
Gitee
From f6ac2a01a7b9f324095ed474a1e46a806932cd65 Mon Sep 17 00:00:00 2001
From: "1437892690@qq.com" <1437892690@qq.com>
Date: Tue, 18 Nov 2025 16:06:05 +0800
Subject: [PATCH 13/18] =?UTF-8?q?[=E5=8A=9F=E8=83=BD]=20=E6=95=B0=E6=8D=AE?=
=?UTF-8?q?=E5=BA=93=E8=BF=9E=E6=8E=A5=E6=B1=A0=E8=8E=B7=E5=8F=96=E4=B8=8D?=
=?UTF-8?q?=E5=88=B0=E8=BF=9E=E6=8E=A5=E6=97=B6=E8=AE=B0=E5=BD=95=E7=BA=BF?=
=?UTF-8?q?=E7=A8=8B=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
关联 #[1551594485678080]数据库连接池获取不到连接时记录线程信息 http://192.168.0.96:8090/demo/rdm.html#/story-detail/939050947543040/939050947543042/1551594485678080
---
.../store/mysql/NeatLogicBasicDataSource.java | 86 ++++++++++---------
1 file changed, 44 insertions(+), 42 deletions(-)
diff --git a/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java b/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
index 807921288..e98703ac2 100644
--- a/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
+++ b/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
@@ -34,49 +34,45 @@ import java.sql.Statement;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
public class NeatLogicBasicDataSource extends HikariDataSource {//替换dbcp2的BasicDataSource
private static final Logger logger = LoggerFactory.getLogger(NeatLogicBasicDataSource.class);
// 保存上次输出日志的时间毫秒数
- private static volatile long lastAuditMilliseconds = -1;
- private static volatile int count = 0;
-
+ private final static AtomicLong lastAuditMilliseconds = new AtomicLong(0);
+ private final static AtomicInteger count = new AtomicInteger(3);
/**
* 五分钟内只打印三次日志
*/
- private synchronized void audit(DataSourceInfoVo dataSourceInfoVo, Map thread2ExecutingSQLMap) {
- boolean flag = false;
- long currentTimeMillis = System.currentTimeMillis();
- long interval = currentTimeMillis - lastAuditMilliseconds;
- if (interval > TimeUnit.MINUTES.toMillis(5)) {
- lastAuditMilliseconds = currentTimeMillis;
- count = 1;
- flag = true;
- } else {
- if (count < 3) {
- count++;
- flag = true;
+ private synchronized void audit() {
+ try {
+ DataSourceInfoVo dataSourceInfoVo = new DataSourceInfoVo();
+ dataSourceInfoVo.setPoolName(this.getPoolName());
+ HikariPoolMXBean hikariPoolMXBean = this.getHikariPoolMXBean();
+ if (hikariPoolMXBean != null) {
+ dataSourceInfoVo.setIdleConnections(hikariPoolMXBean.getIdleConnections());
+ dataSourceInfoVo.setActiveConnections(hikariPoolMXBean.getActiveConnections());
+ dataSourceInfoVo.setThreadsAwaitingConnection(hikariPoolMXBean.getThreadsAwaitingConnection());
+ dataSourceInfoVo.setTotalConnections(hikariPoolMXBean.getTotalConnections());
}
- }
- if (flag) {
- try {
- StringWriter writer = new StringWriter();
- ThreadUtil.dumpTraces(writer);
- writer.write("=================正在执行的SQL语句有" + thread2ExecutingSQLMap.size() + "条=================");
+ Map thread2ExecutingSQLMap = ExecutingSQLInterceptor.getThread2ExecutingSQLMap();
+ StringWriter writer = new StringWriter();
+ ThreadUtil.dumpTraces(writer);
+ writer.write("=================正在执行的SQL语句有" + thread2ExecutingSQLMap.size() + "条=================");
+ writer.write(System.lineSeparator());
+ for (Map.Entry entry : thread2ExecutingSQLMap.entrySet()) {
+ String key = entry.getKey();
+ String value = entry.getValue();
+ writer.write("[" + key + "] 线程正在执行 " + value);
writer.write(System.lineSeparator());
- for (Map.Entry entry : thread2ExecutingSQLMap.entrySet()) {
- String key = entry.getKey();
- String value = entry.getValue();
- writer.write("[" + key + "] 线程正在执行 " + value);
- writer.write(System.lineSeparator());
- }
- writer.write("连接池信息: " + JSON.toJSONString(dataSourceInfoVo));
- Logger SQLTransientConnectionExceptionAuditLogger = LoggerFactory.getLogger("SQLTransientConnectionExceptionAudit");
- SQLTransientConnectionExceptionAuditLogger.error(writer.toString());
- } catch (IOException e) {
- logger.error(e.getMessage(), e);
}
+ writer.write("连接池信息: " + JSON.toJSONString(dataSourceInfoVo));
+ Logger SQLTransientConnectionExceptionAuditLogger = LoggerFactory.getLogger("SQLTransientConnectionExceptionAudit");
+ SQLTransientConnectionExceptionAuditLogger.error(writer.toString());
+ } catch (IOException e) {
+ logger.error(e.getMessage(), e);
}
}
@@ -86,17 +82,23 @@ public class NeatLogicBasicDataSource extends HikariDataSource {//替换dbcp2的
try {
conn = super.getConnection();
} catch (CannotGetJdbcConnectionException | SQLTransientConnectionException ex) {
- DataSourceInfoVo dataSourceInfoVo = new DataSourceInfoVo();
- dataSourceInfoVo.setPoolName(this.getPoolName());
- HikariPoolMXBean hikariPoolMXBean = this.getHikariPoolMXBean();
- if (hikariPoolMXBean != null) {
- dataSourceInfoVo.setIdleConnections(hikariPoolMXBean.getIdleConnections());
- dataSourceInfoVo.setActiveConnections(hikariPoolMXBean.getActiveConnections());
- dataSourceInfoVo.setThreadsAwaitingConnection(hikariPoolMXBean.getThreadsAwaitingConnection());
- dataSourceInfoVo.setTotalConnections(hikariPoolMXBean.getTotalConnections());
+ // 五分钟内只打印三次日志
+ boolean flag = false;
+ long currentTimeMillis = System.currentTimeMillis();
+ long l = lastAuditMilliseconds.getAndUpdate(operand -> currentTimeMillis);
+ long interval = currentTimeMillis - l;
+ if (interval > TimeUnit.MINUTES.toMillis(5)) {
+ count.compareAndSet(3, 1);
+ flag = true;
+ } else {
+ if (count.get() < 3) {
+ count.incrementAndGet();
+ flag = true;
+ }
+ }
+ if (flag) {
+ audit();
}
- Map thread2ExecutingSQLMap = ExecutingSQLInterceptor.getThread2ExecutingSQLMap();
- audit(dataSourceInfoVo, thread2ExecutingSQLMap);
throw ex;
}
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
--
Gitee
From 7a5656611b0f1bf505edfcd6c209ac57c1da1a0c Mon Sep 17 00:00:00 2001
From: "1437892690@qq.com" <1437892690@qq.com>
Date: Tue, 18 Nov 2025 18:01:21 +0800
Subject: [PATCH 14/18] =?UTF-8?q?[=E5=8A=9F=E8=83=BD]=20=E6=95=B0=E6=8D=AE?=
=?UTF-8?q?=E5=BA=93=E8=BF=9E=E6=8E=A5=E6=B1=A0=E8=8E=B7=E5=8F=96=E4=B8=8D?=
=?UTF-8?q?=E5=88=B0=E8=BF=9E=E6=8E=A5=E6=97=B6=E8=AE=B0=E5=BD=95=E7=BA=BF?=
=?UTF-8?q?=E7=A8=8B=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
关联 #[1551594485678080]数据库连接池获取不到连接时记录线程信息 http://192.168.0.96:8090/demo/rdm.html#/story-detail/939050947543040/939050947543042/1551594485678080
---
.../store/mysql/NeatLogicBasicDataSource.java | 25 ++++++++++++-------
1 file changed, 16 insertions(+), 9 deletions(-)
diff --git a/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java b/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
index e98703ac2..6668c9e43 100644
--- a/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
+++ b/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
@@ -40,9 +40,9 @@ import java.util.concurrent.atomic.AtomicLong;
public class NeatLogicBasicDataSource extends HikariDataSource {//替换dbcp2的BasicDataSource
private static final Logger logger = LoggerFactory.getLogger(NeatLogicBasicDataSource.class);
- // 保存上次输出日志的时间毫秒数
- private final static AtomicLong lastAuditMilliseconds = new AtomicLong(0);
- private final static AtomicInteger count = new AtomicInteger(3);
+ // 保存上次抛异常的时间毫秒数
+ private final static AtomicLong lastThrowExceptionMillisecondsAtomicLong = new AtomicLong(0);
+ private final static AtomicInteger countAtomicInteger = new AtomicInteger(3);
/**
* 五分钟内只打印三次日志
*/
@@ -85,14 +85,21 @@ public class NeatLogicBasicDataSource extends HikariDataSource {//替换dbcp2的
// 五分钟内只打印三次日志
boolean flag = false;
long currentTimeMillis = System.currentTimeMillis();
- long l = lastAuditMilliseconds.getAndUpdate(operand -> currentTimeMillis);
- long interval = currentTimeMillis - l;
+ long lastThrowExceptionMilliseconds = lastThrowExceptionMillisecondsAtomicLong.getAndUpdate(operand -> currentTimeMillis);
+ long interval = currentTimeMillis - lastThrowExceptionMilliseconds;
if (interval > TimeUnit.MINUTES.toMillis(5)) {
- count.compareAndSet(3, 1);
- flag = true;
+ if (countAtomicInteger.compareAndSet(3, 0)) {
+ flag = true;
+ }
} else {
- if (count.get() < 3) {
- count.incrementAndGet();
+ int count = countAtomicInteger.updateAndGet(operand -> {
+ if (operand < 3) {
+ return operand + 1;
+ } else {
+ return operand;
+ }
+ });
+ if (count < 3) {
flag = true;
}
}
--
Gitee
From 615a2f13073a7ae6a87e8cd7dc7d1396539f8c5f Mon Sep 17 00:00:00 2001
From: "1437892690@qq.com" <1437892690@qq.com>
Date: Wed, 19 Nov 2025 08:22:30 +0800
Subject: [PATCH 15/18] =?UTF-8?q?[=E5=8A=9F=E8=83=BD]=20=E6=95=B0=E6=8D=AE?=
=?UTF-8?q?=E5=BA=93=E8=BF=9E=E6=8E=A5=E6=B1=A0=E8=8E=B7=E5=8F=96=E4=B8=8D?=
=?UTF-8?q?=E5=88=B0=E8=BF=9E=E6=8E=A5=E6=97=B6=E8=AE=B0=E5=BD=95=E7=BA=BF?=
=?UTF-8?q?=E7=A8=8B=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
关联 #[1551594485678080]数据库连接池获取不到连接时记录线程信息 http://192.168.0.96:8090/demo/rdm.html#/story-detail/939050947543040/939050947543042/1551594485678080
---
.../dao/plugin/ExecutingSQLInterceptor.java | 37 +++---
.../store/mysql/NeatLogicBasicDataSource.java | 74 +----------
.../SQLTransientConnectionExceptionAudit.java | 118 ++++++++++++++++++
3 files changed, 136 insertions(+), 93 deletions(-)
create mode 100644 src/main/java/neatlogic/framework/store/mysql/SQLTransientConnectionExceptionAudit.java
diff --git a/src/main/java/neatlogic/framework/dao/plugin/ExecutingSQLInterceptor.java b/src/main/java/neatlogic/framework/dao/plugin/ExecutingSQLInterceptor.java
index f01211b4c..1b4cf8298 100644
--- a/src/main/java/neatlogic/framework/dao/plugin/ExecutingSQLInterceptor.java
+++ b/src/main/java/neatlogic/framework/dao/plugin/ExecutingSQLInterceptor.java
@@ -13,6 +13,9 @@
package neatlogic.framework.dao.plugin;
import neatlogic.framework.asynchronization.threadlocal.InterceptorContext;
+import neatlogic.framework.common.config.Config;
+import neatlogic.framework.store.mysql.SQLTransientConnectionExceptionAudit;
+import neatlogic.framework.util.SnowflakeUtil;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
@@ -22,9 +25,6 @@ import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import java.sql.Statement;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
@Intercepts({
@Signature(type = StatementHandler.class, method = "batch", args = {Statement.class}),
@@ -34,28 +34,23 @@ import java.util.concurrent.ConcurrentHashMap;
})
public class ExecutingSQLInterceptor implements Interceptor {
- private final static Map thread2ExecutingSQLMap = new ConcurrentHashMap<>();
-
- public static Map getThread2ExecutingSQLMap() {
- return new HashMap<>(thread2ExecutingSQLMap);
- }
-
- public static void clearThread2ExecutingSQLMap() {
- thread2ExecutingSQLMap.clear();
- }
-
@Override
public Object intercept(Invocation invocation) throws Throwable {
- try {
- InterceptorContext interceptorContext = InterceptorContext.get();
- if (interceptorContext != null) {
- MappedStatement mappedStatement = interceptorContext.getMappedStatement();
- String sqlId = mappedStatement.getId();
- thread2ExecutingSQLMap.put(Thread.currentThread().getName(), sqlId);
+ if (Config.DATASOURCE_SQL_TRANSIENT_CONNECTION_EXCEPTION_AUDIT_ENABLE()) {
+ String key = Thread.currentThread().getName() + "#" + SnowflakeUtil.uniqueLong();
+ try {
+ InterceptorContext interceptorContext = InterceptorContext.get();
+ if (interceptorContext != null) {
+ MappedStatement mappedStatement = interceptorContext.getMappedStatement();
+ String sqlId = mappedStatement.getId();
+ SQLTransientConnectionExceptionAudit.putExecutingSQL(key, sqlId);
+ }
+ return invocation.proceed();
+ } finally {
+ SQLTransientConnectionExceptionAudit.removeExecutingSQL(key);
}
+ } else {
return invocation.proceed();
- } finally {
- thread2ExecutingSQLMap.remove(Thread.currentThread().getName());
}
}
}
diff --git a/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java b/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
index 6668c9e43..b124e19d5 100644
--- a/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
+++ b/src/main/java/neatlogic/framework/store/mysql/NeatLogicBasicDataSource.java
@@ -12,69 +12,22 @@
package neatlogic.framework.store.mysql;
-import com.alibaba.fastjson.JSON;
import com.zaxxer.hikari.HikariDataSource;
-import com.zaxxer.hikari.HikariPoolMXBean;
import neatlogic.framework.asynchronization.threadlocal.UserContext;
import neatlogic.framework.common.util.RC4Util;
-import neatlogic.framework.dao.plugin.ExecutingSQLInterceptor;
-import neatlogic.framework.dto.healthcheck.DataSourceInfoVo;
-import neatlogic.framework.util.ThreadUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.CannotGetJdbcConnectionException;
-import java.io.IOException;
-import java.io.StringWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLTransientConnectionException;
import java.sql.Statement;
-import java.util.Map;
import java.util.Objects;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
public class NeatLogicBasicDataSource extends HikariDataSource {//替换dbcp2的BasicDataSource
- private static final Logger logger = LoggerFactory.getLogger(NeatLogicBasicDataSource.class);
-
- // 保存上次抛异常的时间毫秒数
- private final static AtomicLong lastThrowExceptionMillisecondsAtomicLong = new AtomicLong(0);
- private final static AtomicInteger countAtomicInteger = new AtomicInteger(3);
- /**
- * 五分钟内只打印三次日志
- */
- private synchronized void audit() {
- try {
- DataSourceInfoVo dataSourceInfoVo = new DataSourceInfoVo();
- dataSourceInfoVo.setPoolName(this.getPoolName());
- HikariPoolMXBean hikariPoolMXBean = this.getHikariPoolMXBean();
- if (hikariPoolMXBean != null) {
- dataSourceInfoVo.setIdleConnections(hikariPoolMXBean.getIdleConnections());
- dataSourceInfoVo.setActiveConnections(hikariPoolMXBean.getActiveConnections());
- dataSourceInfoVo.setThreadsAwaitingConnection(hikariPoolMXBean.getThreadsAwaitingConnection());
- dataSourceInfoVo.setTotalConnections(hikariPoolMXBean.getTotalConnections());
- }
- Map thread2ExecutingSQLMap = ExecutingSQLInterceptor.getThread2ExecutingSQLMap();
- StringWriter writer = new StringWriter();
- ThreadUtil.dumpTraces(writer);
- writer.write("=================正在执行的SQL语句有" + thread2ExecutingSQLMap.size() + "条=================");
- writer.write(System.lineSeparator());
- for (Map.Entry entry : thread2ExecutingSQLMap.entrySet()) {
- String key = entry.getKey();
- String value = entry.getValue();
- writer.write("[" + key + "] 线程正在执行 " + value);
- writer.write(System.lineSeparator());
- }
- writer.write("连接池信息: " + JSON.toJSONString(dataSourceInfoVo));
- Logger SQLTransientConnectionExceptionAuditLogger = LoggerFactory.getLogger("SQLTransientConnectionExceptionAudit");
- SQLTransientConnectionExceptionAuditLogger.error(writer.toString());
- } catch (IOException e) {
- logger.error(e.getMessage(), e);
- }
- }
+ private final Logger logger = LoggerFactory.getLogger(NeatLogicBasicDataSource.class);
@Override
public Connection getConnection() throws SQLException {
@@ -82,30 +35,7 @@ public class NeatLogicBasicDataSource extends HikariDataSource {//替换dbcp2的
try {
conn = super.getConnection();
} catch (CannotGetJdbcConnectionException | SQLTransientConnectionException ex) {
- // 五分钟内只打印三次日志
- boolean flag = false;
- long currentTimeMillis = System.currentTimeMillis();
- long lastThrowExceptionMilliseconds = lastThrowExceptionMillisecondsAtomicLong.getAndUpdate(operand -> currentTimeMillis);
- long interval = currentTimeMillis - lastThrowExceptionMilliseconds;
- if (interval > TimeUnit.MINUTES.toMillis(5)) {
- if (countAtomicInteger.compareAndSet(3, 0)) {
- flag = true;
- }
- } else {
- int count = countAtomicInteger.updateAndGet(operand -> {
- if (operand < 3) {
- return operand + 1;
- } else {
- return operand;
- }
- });
- if (count < 3) {
- flag = true;
- }
- }
- if (flag) {
- audit();
- }
+ SQLTransientConnectionExceptionAudit.audit();
throw ex;
}
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
diff --git a/src/main/java/neatlogic/framework/store/mysql/SQLTransientConnectionExceptionAudit.java b/src/main/java/neatlogic/framework/store/mysql/SQLTransientConnectionExceptionAudit.java
new file mode 100644
index 000000000..ce748d737
--- /dev/null
+++ b/src/main/java/neatlogic/framework/store/mysql/SQLTransientConnectionExceptionAudit.java
@@ -0,0 +1,118 @@
+/*
+ *
+ * Copyright (C) 2025 TechSure Co., Ltd. All Rights Reserved.
+ * This file is part of the NeatLogic software.
+ * Licensed under the NeatLogic Sustainable Use License (NSUL), Version 4.x – 2025.
+ * You may use this file only in compliance with the License.
+ * See the LICENSE file distributed with this work for the full license text.
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+package neatlogic.framework.store.mysql;
+
+import com.alibaba.fastjson.JSON;
+import com.zaxxer.hikari.HikariPoolMXBean;
+import neatlogic.framework.common.config.Config;
+import neatlogic.framework.dto.healthcheck.DataSourceInfoVo;
+import neatlogic.framework.util.ThreadUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+public class SQLTransientConnectionExceptionAudit {
+
+ private static final Logger logger = LoggerFactory.getLogger(SQLTransientConnectionExceptionAudit.class);
+
+ // 保存上次抛异常的时间毫秒数
+ private final static AtomicLong lastThrowExceptionMillisecondsAtomicLong = new AtomicLong(0);
+ private final static AtomicInteger countAtomicInteger = new AtomicInteger(3);
+ private final static Map executingSQLMap = new ConcurrentHashMap<>();
+
+ public static Map getExecutingSQL() {
+ return new HashMap<>(executingSQLMap);
+ }
+
+ public static void clearExecutingSQL() {
+ executingSQLMap.clear();
+ }
+
+ public static void putExecutingSQL(String key, String value) {
+ executingSQLMap.put(key, value);
+ }
+
+ public static void removeExecutingSQL(String key) {
+ executingSQLMap.remove(key);
+ }
+
+ /**
+ * 五分钟内只打印三次日志
+ */
+ public static void audit() {
+ if (Config.DATASOURCE_SQL_TRANSIENT_CONNECTION_EXCEPTION_AUDIT_ENABLE()) {
+ boolean flag = false;
+ long currentTimeMillis = System.currentTimeMillis();
+ long lastThrowExceptionMilliseconds = lastThrowExceptionMillisecondsAtomicLong.getAndUpdate(operand -> currentTimeMillis);
+ long interval = currentTimeMillis - lastThrowExceptionMilliseconds;
+ if (interval > TimeUnit.MINUTES.toMillis(5)) {
+ if (countAtomicInteger.compareAndSet(3, 0)) {
+ flag = true;
+ }
+ } else {
+ int count = countAtomicInteger.updateAndGet(operand -> {
+ if (operand < 3) {
+ return operand + 1;
+ } else {
+ return operand;
+ }
+ });
+ if (count < 3) {
+ flag = true;
+ }
+ }
+ if (flag) {
+ doAudit();
+ }
+ }
+ }
+
+ private static synchronized void doAudit() {
+ try {
+ DataSourceInfoVo dataSourceInfoVo = new DataSourceInfoVo();
+ NeatLogicBasicDataSource datasource = DatasourceManager.getDatasource();
+ dataSourceInfoVo.setPoolName(datasource.getPoolName());
+ HikariPoolMXBean hikariPoolMXBean = datasource.getHikariPoolMXBean();
+ if (hikariPoolMXBean != null) {
+ dataSourceInfoVo.setIdleConnections(hikariPoolMXBean.getIdleConnections());
+ dataSourceInfoVo.setActiveConnections(hikariPoolMXBean.getActiveConnections());
+ dataSourceInfoVo.setThreadsAwaitingConnection(hikariPoolMXBean.getThreadsAwaitingConnection());
+ dataSourceInfoVo.setTotalConnections(hikariPoolMXBean.getTotalConnections());
+ }
+ Map executingSQLSnapshotMap = new HashMap<>(executingSQLMap);
+ StringWriter writer = new StringWriter();
+ ThreadUtil.dumpTraces(writer);
+ writer.write("=================正在执行的SQL语句有" + executingSQLSnapshotMap.size() + "条=================");
+ writer.write(System.lineSeparator());
+ for (Map.Entry entry : executingSQLSnapshotMap.entrySet()) {
+ String key = entry.getKey();
+ String value = entry.getValue();
+ writer.write("[" + key + "] 线程正在执行 " + value);
+ writer.write(System.lineSeparator());
+ }
+ writer.write("连接池信息: " + JSON.toJSONString(dataSourceInfoVo));
+ Logger SQLTransientConnectionExceptionAuditLogger = LoggerFactory.getLogger("SQLTransientConnectionExceptionAudit");
+ SQLTransientConnectionExceptionAuditLogger.error(writer.toString());
+ } catch (IOException e) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+}
--
Gitee
From 83284bb8cb4c4f940dafa0fbc44afbf007214bcf Mon Sep 17 00:00:00 2001
From: "1437892690@qq.com" <1437892690@qq.com>
Date: Wed, 19 Nov 2025 08:23:24 +0800
Subject: [PATCH 16/18] =?UTF-8?q?[=E5=8A=9F=E8=83=BD]=20=E6=95=B0=E6=8D=AE?=
=?UTF-8?q?=E5=BA=93=E8=BF=9E=E6=8E=A5=E6=B1=A0=E8=8E=B7=E5=8F=96=E4=B8=8D?=
=?UTF-8?q?=E5=88=B0=E8=BF=9E=E6=8E=A5=E6=97=B6=E8=AE=B0=E5=BD=95=E7=BA=BF?=
=?UTF-8?q?=E7=A8=8B=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
关联 #[1551594485678080]数据库连接池获取不到连接时记录线程信息 http://192.168.0.96:8090/demo/rdm.html#/story-detail/939050947543040/939050947543042/1551594485678080
---
.../neatlogic/framework/common/config/Config.java | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/src/main/java/neatlogic/framework/common/config/Config.java b/src/main/java/neatlogic/framework/common/config/Config.java
index 4ed2d325a..5e143f451 100644
--- a/src/main/java/neatlogic/framework/common/config/Config.java
+++ b/src/main/java/neatlogic/framework/common/config/Config.java
@@ -54,7 +54,7 @@ public class Config {
private static String DB_HOST;
private static Integer DB_PORT;
private static String DB_URL;
- private static String DB_TRANSACTION_TIMEOUT;// 事务超时时间
+ private static Integer DB_TRANSACTION_TIMEOUT;// 事务超时时间
private static int DATASOURCE_CONNECT_TIMEOUT;//连接池连接超时时间
private static Integer DATASOURCE_MAXIMUM_POOL_SIZE;//连接数
private static Integer DATASOURCE_MAX_LIFETIME;//控制池中连接的最大生存期
@@ -62,6 +62,7 @@ public class Config {
private static Integer DATASOURCE_VALIDATION_TIMEOUT;//此属性控制测试连接是否活跃的最长时间。此值必须小于 connectionTimeout
private static Integer DATASOURCE_IDLE_TIMEOUT;//此属性控制允许连接在池中处于空闲状态的最长时间
private static Long DATASOURCE_KEEPALIVE_TIME;//此属性控制允许连接在池中心跳时间,不能比DATASOURCE_MAX_LIFETIME大
+ private static Boolean DATASOURCE_SQL_TRANSIENT_CONNECTION_EXCEPTION_AUDIT_ENABLE; // 开启数据库连接获取异常日志
private static String DATA_HOME;// 存储文件路径
private static String AUDIT_HOME;// 审计日志存储文件路径
private static int SERVER_HEARTBEAT_RATE;// 心跳频率
@@ -249,7 +250,7 @@ public class Config {
return DB_URL;
}
- public static String DB_TRANSACTION_TIMEOUT() {// root-context.xml中使用了该变量
+ public static Integer DB_TRANSACTION_TIMEOUT() {// root-context.xml中使用了该变量
return DB_TRANSACTION_TIMEOUT;
}
@@ -281,6 +282,10 @@ public class Config {
return DATASOURCE_IDLE_TIMEOUT;
}
+ public static Boolean DATASOURCE_SQL_TRANSIENT_CONNECTION_EXCEPTION_AUDIT_ENABLE() {
+ return DATASOURCE_SQL_TRANSIENT_CONNECTION_EXCEPTION_AUDIT_ENABLE;
+ }
+
public static String JMS_URL() {
return JMS_URL;
}
@@ -628,14 +633,15 @@ public class Config {
USER_EXPIRETIME = prop.getProperty("user.expiretime", "60");
LOGIN_CAPTCHA_EXPIRED_TIME = Integer.parseInt(prop.getProperty("login.captcha.expired.time", "60"));
LOGIN_FAILED_TIMES_CAPTCHA = Integer.parseInt(prop.getProperty("login.failed.times.captcha", "3"));
- DB_TRANSACTION_TIMEOUT = prop.getProperty("db.transaction.timeout");
+ DB_TRANSACTION_TIMEOUT = Integer.parseInt(prop.getProperty("db.transaction.timeout"));
DATASOURCE_CONNECT_TIMEOUT = Integer.parseInt(prop.getProperty("datasource.connect.timeout", "5000"));
- DATASOURCE_MAXIMUM_POOL_SIZE = Integer.parseInt(prop.getProperty("datasource.maximum.pool.size", "250"));
+ DATASOURCE_MAXIMUM_POOL_SIZE = Integer.parseInt(prop.getProperty("datasource.maximum.pool.size", "20"));
DATASOURCE_KEEPALIVE_TIME = Long.parseLong(prop.getProperty("datasource.keepalive.time", "180000"));
DATASOURCE_MAX_LIFETIME = Integer.parseInt(prop.getProperty("datasource.max.lifetime", "1800000"));
DATASOURCE_MINIMUM_IDLE = Integer.parseInt(prop.getProperty("datasource.minimum.idle", "20"));
DATASOURCE_VALIDATION_TIMEOUT = Integer.parseInt(prop.getProperty("datasource.validation.timeout", "5000"));
DATASOURCE_IDLE_TIMEOUT = Integer.parseInt(prop.getProperty("datasource.idle.timeout", "600000"));
+ DATASOURCE_SQL_TRANSIENT_CONNECTION_EXCEPTION_AUDIT_ENABLE = Boolean.parseBoolean(prop.getProperty("datasource.sql.transient.connection.exception.audit.enable", "true"));
DB_URL = prop.getProperty("db.url");
DB_HOST = prop.getProperty("db.host", "localhost");
DB_PORT = Integer.parseInt(prop.getProperty("db.port", "3306"));
--
Gitee
From 1b8974c57d782fd7f38ad1a21c5997e2205ab536 Mon Sep 17 00:00:00 2001
From: "1437892690@qq.com" <1437892690@qq.com>
Date: Wed, 19 Nov 2025 08:26:23 +0800
Subject: [PATCH 17/18] =?UTF-8?q?[=E5=8A=9F=E8=83=BD]=20=E6=95=B0=E6=8D=AE?=
=?UTF-8?q?=E5=BA=93=E8=BF=9E=E6=8E=A5=E6=B1=A0=E8=8E=B7=E5=8F=96=E4=B8=8D?=
=?UTF-8?q?=E5=88=B0=E8=BF=9E=E6=8E=A5=E6=97=B6=E8=AE=B0=E5=BD=95=E7=BA=BF?=
=?UTF-8?q?=E7=A8=8B=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
关联 #[1551594485678080]数据库连接池获取不到连接时记录线程信息 http://192.168.0.96:8090/demo/rdm.html#/story-detail/939050947543040/939050947543042/1551594485678080
---
src/main/java/neatlogic/framework/common/config/Config.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/neatlogic/framework/common/config/Config.java b/src/main/java/neatlogic/framework/common/config/Config.java
index 5e143f451..ca48644c6 100644
--- a/src/main/java/neatlogic/framework/common/config/Config.java
+++ b/src/main/java/neatlogic/framework/common/config/Config.java
@@ -635,7 +635,7 @@ public class Config {
LOGIN_FAILED_TIMES_CAPTCHA = Integer.parseInt(prop.getProperty("login.failed.times.captcha", "3"));
DB_TRANSACTION_TIMEOUT = Integer.parseInt(prop.getProperty("db.transaction.timeout"));
DATASOURCE_CONNECT_TIMEOUT = Integer.parseInt(prop.getProperty("datasource.connect.timeout", "5000"));
- DATASOURCE_MAXIMUM_POOL_SIZE = Integer.parseInt(prop.getProperty("datasource.maximum.pool.size", "20"));
+ DATASOURCE_MAXIMUM_POOL_SIZE = Integer.parseInt(prop.getProperty("datasource.maximum.pool.size", "250"));
DATASOURCE_KEEPALIVE_TIME = Long.parseLong(prop.getProperty("datasource.keepalive.time", "180000"));
DATASOURCE_MAX_LIFETIME = Integer.parseInt(prop.getProperty("datasource.max.lifetime", "1800000"));
DATASOURCE_MINIMUM_IDLE = Integer.parseInt(prop.getProperty("datasource.minimum.idle", "20"));
--
Gitee
From a486731c28458eeb6e4ea6ef6f892a45036f4b12 Mon Sep 17 00:00:00 2001
From: "1437892690@qq.com" <1437892690@qq.com>
Date: Wed, 19 Nov 2025 10:32:08 +0800
Subject: [PATCH 18/18] =?UTF-8?q?[=E5=8A=9F=E8=83=BD]=20=E6=95=B0=E6=8D=AE?=
=?UTF-8?q?=E5=BA=93=E8=BF=9E=E6=8E=A5=E6=B1=A0=E8=8E=B7=E5=8F=96=E4=B8=8D?=
=?UTF-8?q?=E5=88=B0=E8=BF=9E=E6=8E=A5=E6=97=B6=E8=AE=B0=E5=BD=95=E7=BA=BF?=
=?UTF-8?q?=E7=A8=8B=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
关联 #[1551594485678080]数据库连接池获取不到连接时记录线程信息 http://192.168.0.96:8090/demo/rdm.html#/story-detail/939050947543040/939050947543042/1551594485678080
---
.../java/neatlogic/framework/common/config/Config.java | 8 ++++----
.../framework/dao/plugin/ExecutingSQLInterceptor.java | 3 ++-
.../store/mysql/SQLTransientConnectionExceptionAudit.java | 3 ++-
3 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/src/main/java/neatlogic/framework/common/config/Config.java b/src/main/java/neatlogic/framework/common/config/Config.java
index ca48644c6..ceed926a7 100644
--- a/src/main/java/neatlogic/framework/common/config/Config.java
+++ b/src/main/java/neatlogic/framework/common/config/Config.java
@@ -62,7 +62,7 @@ public class Config {
private static Integer DATASOURCE_VALIDATION_TIMEOUT;//此属性控制测试连接是否活跃的最长时间。此值必须小于 connectionTimeout
private static Integer DATASOURCE_IDLE_TIMEOUT;//此属性控制允许连接在池中处于空闲状态的最长时间
private static Long DATASOURCE_KEEPALIVE_TIME;//此属性控制允许连接在池中心跳时间,不能比DATASOURCE_MAX_LIFETIME大
- private static Boolean DATASOURCE_SQL_TRANSIENT_CONNECTION_EXCEPTION_AUDIT_ENABLE; // 开启数据库连接获取异常日志
+ private static Integer DATASOURCE_EXCEPTION_AUDIT; // 开启数据库连接获取异常日志
private static String DATA_HOME;// 存储文件路径
private static String AUDIT_HOME;// 审计日志存储文件路径
private static int SERVER_HEARTBEAT_RATE;// 心跳频率
@@ -282,8 +282,8 @@ public class Config {
return DATASOURCE_IDLE_TIMEOUT;
}
- public static Boolean DATASOURCE_SQL_TRANSIENT_CONNECTION_EXCEPTION_AUDIT_ENABLE() {
- return DATASOURCE_SQL_TRANSIENT_CONNECTION_EXCEPTION_AUDIT_ENABLE;
+ public static Integer DATASOURCE_EXCEPTION_AUDIT() {
+ return DATASOURCE_EXCEPTION_AUDIT;
}
public static String JMS_URL() {
@@ -641,7 +641,7 @@ public class Config {
DATASOURCE_MINIMUM_IDLE = Integer.parseInt(prop.getProperty("datasource.minimum.idle", "20"));
DATASOURCE_VALIDATION_TIMEOUT = Integer.parseInt(prop.getProperty("datasource.validation.timeout", "5000"));
DATASOURCE_IDLE_TIMEOUT = Integer.parseInt(prop.getProperty("datasource.idle.timeout", "600000"));
- DATASOURCE_SQL_TRANSIENT_CONNECTION_EXCEPTION_AUDIT_ENABLE = Boolean.parseBoolean(prop.getProperty("datasource.sql.transient.connection.exception.audit.enable", "true"));
+ DATASOURCE_EXCEPTION_AUDIT = Integer.parseInt(prop.getProperty("datasource.exception.audit", "1"));
DB_URL = prop.getProperty("db.url");
DB_HOST = prop.getProperty("db.host", "localhost");
DB_PORT = Integer.parseInt(prop.getProperty("db.port", "3306"));
diff --git a/src/main/java/neatlogic/framework/dao/plugin/ExecutingSQLInterceptor.java b/src/main/java/neatlogic/framework/dao/plugin/ExecutingSQLInterceptor.java
index 1b4cf8298..b609e8ee0 100644
--- a/src/main/java/neatlogic/framework/dao/plugin/ExecutingSQLInterceptor.java
+++ b/src/main/java/neatlogic/framework/dao/plugin/ExecutingSQLInterceptor.java
@@ -25,6 +25,7 @@ import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import java.sql.Statement;
+import java.util.Objects;
@Intercepts({
@Signature(type = StatementHandler.class, method = "batch", args = {Statement.class}),
@@ -36,7 +37,7 @@ public class ExecutingSQLInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
- if (Config.DATASOURCE_SQL_TRANSIENT_CONNECTION_EXCEPTION_AUDIT_ENABLE()) {
+ if (Objects.equals(Config.DATASOURCE_EXCEPTION_AUDIT(), 1)) {
String key = Thread.currentThread().getName() + "#" + SnowflakeUtil.uniqueLong();
try {
InterceptorContext interceptorContext = InterceptorContext.get();
diff --git a/src/main/java/neatlogic/framework/store/mysql/SQLTransientConnectionExceptionAudit.java b/src/main/java/neatlogic/framework/store/mysql/SQLTransientConnectionExceptionAudit.java
index ce748d737..022971998 100644
--- a/src/main/java/neatlogic/framework/store/mysql/SQLTransientConnectionExceptionAudit.java
+++ b/src/main/java/neatlogic/framework/store/mysql/SQLTransientConnectionExceptionAudit.java
@@ -24,6 +24,7 @@ import java.io.IOException;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@@ -58,7 +59,7 @@ public class SQLTransientConnectionExceptionAudit {
* 五分钟内只打印三次日志
*/
public static void audit() {
- if (Config.DATASOURCE_SQL_TRANSIENT_CONNECTION_EXCEPTION_AUDIT_ENABLE()) {
+ if (Objects.equals(Config.DATASOURCE_EXCEPTION_AUDIT(), 1)) {
boolean flag = false;
long currentTimeMillis = System.currentTimeMillis();
long lastThrowExceptionMilliseconds = lastThrowExceptionMillisecondsAtomicLong.getAndUpdate(operand -> currentTimeMillis);
--
Gitee