一次JDBC连接泄露问题的排查过程总结

springboot使用Hikari连接池问题:HikariPool-1 - Connection is not available, request timed out after 30000ms 最近项目由Oracle切mysql,在压测时发现一直会有该错误抛出: HikariPool-1 - Connection is not available, request timed out after 30000ms 我们知道Springboot 2.X默认的是使用的Hikari连接池,抛出上述错误因为拿不到连接了,最大可能是因为连接池的最大连接数设置的小了; 创建连接池和session代码如下: package com.bootMybatis.config; import com.zax 阅读详情

面试:你懂什么是分布式系统吗?Redis分布式锁都不会?>>>   hot3.png

当前使用的Spring JDBC版本是5.0.0.RC1,HikariCP版本是3.1.0。

今天测试同学反馈在前端页面点击次数多了,就报500错误,数据显示不出来。于是我在后台服务日志中观察发现HikariCP连接池报如下的错误:

getDataByWorkSheetId method Exception:HikariPool-2 - Connection is not available, request timed out after 30000ms.

接着开始翻墙搜谷歌,大致要从两方面进行解决:

一、服务端:

1、给业务逻辑层相应的方法加上@Transactional注解,以便启用Spring的事务管理功能,在Spring提交事务之后,自动进行连接资源的释放

2、调整HikariCP连接池的连接参数,比如调整连接池大小以及时间参数

二、数据库端:

调整MySQL数据库的wait_timeout参数。这个参数表示不活动的(noninteractive connection)连接被MySQL服务器关闭之前等待的秒数,默认值是28800秒,换算成小时是8小时。当有线程使用连接时,它会重新被初始化。经过观察发现,当有线程使用akp_test数据库的连接时,相应连接的wait_timeout会清零,然后重新开始计时,直到达到wait_timeout的最大值28800秒。也就是说,不活动的连接如果没有访问,会在达到8小时的空闲时间后被MySQL数据库关闭。

搜索到这个解决办法是因为我用show processlist命令查询了当前操作MySQL数据库的所有运行着的线程,发现操作akp_test数据库的好多连接线程都处于Sleep状态(具体见截图中的Command栏),这种状态表示等待客户端发送操作请求,并且随着时间的推移,Time一栏的时间数值也在逐渐变大,重启连接数据库的应用后这种情况消失,随着访问的增多又逐渐出现了这种现象。Time一栏的时间数值也呈降序排列,此时的访问量并不高,说明每次访问数据库建立的连接可能没有被关闭,导致连接池饱和,出现连接请求超时的问题。

排查过程

经过思考之后,大致可以断定问题出现在访问数据库的方法上,应该是应用操作数据库后连接没有释放引起的连接泄露问题。排查过程如下:

找出访问数据库的方法

我首先尝试了从服务端解决,也就是给业务逻辑层的方法增加@Transactional注解和调整HikariCP连接池的连接参数,都没有效果。最后开始着手从业务逻辑层的getDataByWorkSheetId方法入手查找代码上的问题。getDataByWorkSheetId方法的作用是根据workSheetId去查询相应的业务数据信息,操作数据库用的Spring JDBC的JdbcTemplate类,在getDataByWorkSheetId方法中,分别使用了JdbcTemplate类的两个方法:

  • queryForList(String sql):根据相应的sql语句查询数据,返回一个数据集合

  • getDataSource.getConnection.getMetaData.getColumns(String catalog, String schemaPattern,String tableNamePattern, String columnNamePattern):该方法调用链比较长,但调用逻辑清晰,首先是通过getConnection方法获取数据库连接,然后使用getMetaData获取数据库元数据信息,最后调用getColumns获取tableNamePattern对应的数据库表的信息

于是我开始debug两个方法的实现,找出是哪一个方法没有关闭数据库连接。

访问数据库的方法实现

queryForList方法实现

首先看看JdbcTemplate类的queryForList方法实现,该方法最终调用的是JdbcTemplate类的query(final String sql, final ResultSetExtractor<T> rse)方法和execute(StatementCallback<T> action)方法,两个方法实现代码如下,注意关闭数据库连接部分:

1、query(final String sql, final ResultSetExtractor<T> rse):

public <T> T query(final String sql, final ResultSetExtractor<T> rse) throws DataAccessException {
		Assert.notNull(sql, "SQL must not be null");
		Assert.notNull(rse, "ResultSetExtractor must not be null");
		if (logger.isDebugEnabled()) {
			logger.debug("Executing SQL query [" + sql + "]");
		}
		class QueryStatementCallback implements StatementCallback<T>, SqlProvider {
			@Override
			public T doInStatement(Statement stmt) throws SQLException {
				ResultSet rs = null;
				try {
					rs = stmt.executeQuery(sql);
					return rse.extractData(rs);
				}
				finally {
					// 关闭ResultSet对象
					JdbcUtils.closeResultSet(rs);
				}
			}
			@Override
			public String getSql() {
				return sql;
			}
		}
		return execute(new QueryStatementCallback());
	}

2、execute(StatementCallback<T> action):

public <T> T execute(StatementCallback<T> action) throws DataAccessException {
		Assert.notNull(action, "Callback object must not be null");

		Connection con = DataSourceUtils.getConnection(getDataSource());
		Statement stmt = null;
		try {
			stmt = con.createStatement();
			applyStatementSettings(stmt);
			T result = action.doInStatement(stmt);
			handleWarnings(stmt);
			return result;
		}
		catch (SQLException ex) { // 发生异常时关闭Statement对象和Connection对象
			// Release Connection early, to avoid potential connection pool deadlock
			// in the case when the exception translator hasn't been initialized yet.
			JdbcUtils.closeStatement(stmt);
			stmt = null;
			DataSourceUtils.releaseConnection(con, getDataSource());
			con = null;
			throw getExceptionTranslator().translate("StatementCallback", getSql(action), ex);
		}
		finally {
			// 关闭Statement对象
			JdbcUtils.closeStatement(stmt);
			// 关闭Connection对象
			DataSourceUtils.releaseConnection(con, getDataSource());
		}
	}

从以上代码片段可以看出,queryForList方法在操作数据库完成后,依次关闭了ResultSet对象、Statement对象和Connection对象。

getColumns方法实现

getColumns方法是java.sql.DatabaseMetaData接口的一个方法,该接口主要是用来定义获取数据库信息应有的方法。该接口根据不同的数据库驱动有不同的实现类,部分实现类如下:

由于我当前使用的是MySQL数据库,因此它的实现类是com.mysql.jdbc.JDBC4DatabaseMetaData类,这个类的getColumns方法最终是调用的它的父类com.mysql.jdbc.DatabaseMetaData的getColumns方法:

 public java.sql.ResultSet getColumns(final String catalog, final String schemaPattern, final String tableNamePattern, String columnNamePattern)
            throws SQLException {

        if (columnNamePattern == null) {
            if (this.conn.getNullNamePatternMatchesAll()) {
                columnNamePattern = "%";
            } else {
                throw SQLError.createSQLException("Column name pattern can not be NULL or empty.", SQLError.SQL_STATE_ILLEGAL_ARGUMENT,
                        getExceptionInterceptor());
            }
        }

        final String colPattern = columnNamePattern;

        Field[] fields = createColumnsFields();

        final ArrayList<ResultSetRow> rows = new ArrayList<ResultSetRow>();
        final Statement stmt = this.conn.getMetadataSafeStatement();

        try {

            new IterateBlock<String>(getCatalogIterator(catalog)) {
                @Override
                void forEach(String catalogStr) throws SQLException {

                    ArrayList<String> tableNameList = new ArrayList<String>();

                    if (tableNamePattern == null) {
                        // Select from all tables
                        java.sql.ResultSet tables = null;

                        try {
                            tables = getTables(catalogStr, schemaPattern, "%", new String[0]);

                            while (tables.next()) {
                                String tableNameFromList = tables.getString("TABLE_NAME");
                                tableNameList.add(tableNameFromList);
                            }
                        } finally {
                            if (tables != null) {
                                try {
                                    tables.close();
                                } catch (Exception sqlEx) {
                                    AssertionFailedException.shouldNotHappen(sqlEx);
                                }

                                tables = null;
                            }
                        }
                    } else {
                        java.sql.ResultSet tables = null;

                        try {
                            tables = getTables(catalogStr, schemaPattern, tableNamePattern, new String[0]);

                            while (tables.next()) {
                                String tableNameFromList = tables.getString("TABLE_NAME");
                                tableNameList.add(tableNameFromList);
                            }
                        } finally {
                            if (tables != null) {
                                try {
                                    tables.close();
                                } catch (SQLException sqlEx) {
                                    AssertionFailedException.shouldNotHappen(sqlEx);
                                }

                                tables = null;
                            }
                        }
                    }

                    for (String tableName : tableNameList) {

                        ResultSet results = null;

                        try {
                            StringBuilder queryBuf = new StringBuilder("SHOW ");

                            if (DatabaseMetaData.this.conn.versionMeetsMinimum(4, 1, 0)) {
                                queryBuf.append("FULL ");
                            }

                            queryBuf.append("COLUMNS FROM ");
                            queryBuf.append(StringUtils.quoteIdentifier(tableName, DatabaseMetaData.this.quotedId, DatabaseMetaData.this.conn.getPedantic()));
                            queryBuf.append(" FROM ");
                            queryBuf.append(StringUtils.quoteIdentifier(catalogStr, DatabaseMetaData.this.quotedId, DatabaseMetaData.this.conn.getPedantic()));
                            queryBuf.append(" LIKE ");
                            queryBuf.append(StringUtils.quoteIdentifier(colPattern, "'", true));

                            // Return correct ordinals if column name pattern is not '%'
                            // Currently, MySQL doesn't show enough data to do this, so we do it the 'hard' way...Once _SYSTEM tables are in, this should be
                            // much easier
                            boolean fixUpOrdinalsRequired = false;
                            Map<String, Integer> ordinalFixUpMap = null;

                            if (!colPattern.equals("%")) {
                                fixUpOrdinalsRequired = true;

                                StringBuilder fullColumnQueryBuf = new StringBuilder("SHOW ");

                                if (DatabaseMetaData.this.conn.versionMeetsMinimum(4, 1, 0)) {
                                    fullColumnQueryBuf.append("FULL ");
                                }

                                fullColumnQueryBuf.append("COLUMNS FROM ");
                                fullColumnQueryBuf.append(
                                        StringUtils.quoteIdentifier(tableName, DatabaseMetaData.this.quotedId, DatabaseMetaData.this.conn.getPedantic()));
                                fullColumnQueryBuf.append(" FROM ");
                                fullColumnQueryBuf.append(
                                        StringUtils.quoteIdentifier(catalogStr, DatabaseMetaData.this.quotedId, DatabaseMetaData.this.conn.getPedantic()));

                                results = stmt.executeQuery(fullColumnQueryBuf.toString());

                                ordinalFixUpMap = new HashMap<String, Integer>();

                                int fullOrdinalPos = 1;

                                while (results.next()) {
                                    String fullOrdColName = results.getString("Field");

                                    ordinalFixUpMap.put(fullOrdColName, Integer.valueOf(fullOrdinalPos++));
                                }
                            }

                            results = stmt.executeQuery(queryBuf.toString());

                            int ordPos = 1;

                            while (results.next()) {
                                byte[][] rowVal = new byte[24][];
                                rowVal[0] = s2b(catalogStr); // TABLE_CAT
                                rowVal[1] = null; // TABLE_SCHEM (No schemas
                                // in MySQL)

                                rowVal[2] = s2b(tableName); // TABLE_NAME
                                rowVal[3] = results.getBytes("Field");

                                TypeDescriptor typeDesc = new TypeDescriptor(results.getString("Type"), results.getString("Null"));

                                rowVal[4] = Short.toString(typeDesc.dataType).getBytes();

                                // DATA_TYPE (jdbc)
                                rowVal[5] = s2b(typeDesc.typeName); // TYPE_NAME
                                // (native)
                                if (typeDesc.columnSize == null) {
                                    rowVal[6] = null;
                                } else {
                                    String collation = results.getString("Collation");
                                    int mbminlen = 1;
                                    if (collation != null && ("TEXT".equals(typeDesc.typeName) || "TINYTEXT".equals(typeDesc.typeName)
                                            || "MEDIUMTEXT".equals(typeDesc.typeName))) {
                                        if (collation.indexOf("ucs2") > -1 || collation.indexOf("utf16") > -1) {
                                            mbminlen = 2;
                                        } else if (collation.indexOf("utf32") > -1) {
                                            mbminlen = 4;
                                        }
                                    }
                                    rowVal[6] = mbminlen == 1 ? s2b(typeDesc.columnSize.toString())
                                            : s2b(((Integer) (typeDesc.columnSize / mbminlen)).toString());
                                }
                                rowVal[7] = s2b(Integer.toString(typeDesc.bufferLength));
                                rowVal[8] = typeDesc.decimalDigits == null ? null : s2b(typeDesc.decimalDigits.toString());
                                rowVal[9] = s2b(Integer.toString(typeDesc.numPrecRadix));
                                rowVal[10] = s2b(Integer.toString(typeDesc.nullability));

                                //
                                // Doesn't always have this field, depending on version
                                //
                                //
                                // REMARK column
                                //
                                try {
                                    if (DatabaseMetaData.this.conn.versionMeetsMinimum(4, 1, 0)) {
                                        rowVal[11] = results.getBytes("Comment");
                                    } else {
                                        rowVal[11] = results.getBytes("Extra");
                                    }
                                } catch (Exception E) {
                                    rowVal[11] = new byte[0];
                                }

                                // COLUMN_DEF
                                rowVal[12] = results.getBytes("Default");

                                rowVal[13] = new byte[] { (byte) '0' }; // SQL_DATA_TYPE
                                rowVal[14] = new byte[] { (byte) '0' }; // SQL_DATE_TIME_SUB

                                if (StringUtils.indexOfIgnoreCase(typeDesc.typeName, "CHAR") != -1
                                        || StringUtils.indexOfIgnoreCase(typeDesc.typeName, "BLOB") != -1
                                        || StringUtils.indexOfIgnoreCase(typeDesc.typeName, "TEXT") != -1
                                        || StringUtils.indexOfIgnoreCase(typeDesc.typeName, "BINARY") != -1) {
                                    rowVal[15] = rowVal[6]; // CHAR_OCTET_LENGTH
                                } else {
                                    rowVal[15] = null;
                                }

                                // ORDINAL_POSITION
                                if (!fixUpOrdinalsRequired) {
                                    rowVal[16] = Integer.toString(ordPos++).getBytes();
                                } else {
                                    String origColName = results.getString("Field");
                                    Integer realOrdinal = ordinalFixUpMap.get(origColName);

                                    if (realOrdinal != null) {
                                        rowVal[16] = realOrdinal.toString().getBytes();
                                    } else {
                                        throw SQLError.createSQLException("Can not find column in full column list to determine true ordinal position.",
                                                SQLError.SQL_STATE_GENERAL_ERROR, getExceptionInterceptor());
                                    }
                                }

                                rowVal[17] = s2b(typeDesc.isNullable);

                                // We don't support REF or DISTINCT types
                                rowVal[18] = null;
                                rowVal[19] = null;
                                rowVal[20] = null;
                                rowVal[21] = null;

                                rowVal[22] = s2b("");

                                String extra = results.getString("Extra");

                                if (extra != null) {
                                    rowVal[22] = s2b(StringUtils.indexOfIgnoreCase(extra, "auto_increment") != -1 ? "YES" : "NO");
                                    rowVal[23] = s2b(StringUtils.indexOfIgnoreCase(extra, "generated") != -1 ? "YES" : "NO");
                                }

                                rows.add(new ByteArrayRow(rowVal, getExceptionInterceptor()));
                            }
                        } finally {
                            if (results != null) {
                                try {
                                    results.close();
                                } catch (Exception ex) {
                                }

                                results = null;
                            }
                        }
                    }
                }
            }.doForAll();
        } finally {
            if (stmt != null) {
                stmt.close();
            }
        }

        java.sql.ResultSet results = buildResultSet(fields, rows);

        return results;
    }

通过代码中results.close()和stmt.close()的调用可以看出,该方法只关闭了ResultSet对象和Statement对象,而没有关闭Connection对象。最终在我们调用方法的时候导致了连接泄露,因此我对getColumns方法进行了二次封装:

  /**
    * 获取列信息
    *
    * @param id        数据源ID
    * @param tableName 表名
    * @return ResultSet对象
    */
  def getColumns(id: Int, tableName: String): ResultSet = {
    var connection: Connection = null
    var resultSet: ResultSet = null
    try {
      connection = getJdbcTemplate(id).getDataSource.getConnection
      resultSet = connection.getMetaData.getColumns(null, null, tableName, null)
    } catch {
      case e: Exception => log.error(s"GetColumns exception: ${e.getMessage}, id: $id, tableName: $tableName")
    } finally {
      // 关闭连接
      if (connection != null && !connection.isClosed) {
        connection.close()
      }
    }
    resultSet
  }

封装后的方法对获取的数据库连接使用完毕后执行了关闭操作,经测试,连接泄露问题得以解决。

总结

这次连接泄露问题的产生主要是由于没有关闭数据库连接导致,解决过程大致按先后次序可以总结如下:

1、首先使用show processlist命令查询当前操作MySQL数据库所有运行着的线程,并查看结果集中Command栏和Time栏的数据。如果Command栏中大多数线程的状态是Sleep,并且Time栏的数值不断在增大,并且呈降序排序,说明连接没有被复用,而且访问数据库的应用程序一直在创建新连接。这说明已经产生了连接泄露问题

2、看看方法有没有@Transactiona注解或者使用XML配置方式进行事务管理,或者出问题的方法中有没有主动创建连接未关闭的情况。使用Spring事务管理的方法,都会在事务执行完毕后,释放连接。Spring JDBC中DataSourceUtils类释放连接的代码解释如下:

public static void doReleaseConnection(Connection con, DataSource dataSource) throws SQLException {
		if (con == null) {
			return;
		}
		if (dataSource != null) {
			// 如果使用了事务管理,则调用conHolder.released()释放连接,而不关闭
			ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
			if (conHolder != null && connectionEquals(conHolder, con)) {
				// It's the transactional Connection: Don't close it.
				conHolder.released();
				return;
			}
		}
		logger.debug("Returning JDBC Connection to DataSource");
		// 如果没有事务管理,则调用con.close()关闭连接
		doCloseConnection(con, dataSource);
	}

3、将MySQL数据库的wait_time参数调小。这个要看实际情况,低并发且大多用短连接连接数据库的服务,可以调小,高并发的断开重连会造成MySQL数据库服务器的CPU上下文切换非常严重,也会导致CPU的CS非常高。

4、调整连接池参数。这个根据实际情况做调整吧。

参考链接

show processlist官方解释

show processlist结果中command栏官方解释

mysql wait_timeout参数官方解释

connection is not available, request timed out after问题的GitHub issue

sleep太多的问题解决办法讨论

Spring JDBC-数据连接泄露解读

一次线上故障:数据库连接池泄露后的思考 早上作为能效平台系统的使用高峰期,系统负载通常比其它时间段更大一些,某个时间段会有大量用户登录。当天系统开始有用户报障,发布系统线上无法构建发布,然后后续有用户不能登录系统,系统发生假死,当然系统不是真的宕机,而是所有和数据库有关的连接都被阻塞,随后查看日志发现有大量报错。可以看出上面的报错和数据库连接有关,大量超时。通过对线上debug日志的分析,也验证了数据库连接池被大量消耗。这是开始大量报错前的日志。... 阅读详情

相关推荐

从一次线上数据库连接泄露排查,我重新认识了Spring Boot的Hikari连接池

本文通过一次线上数据库连接泄露故障排查,深入分析了Spring Boot中Hikari连接池的工作原理和配置方法。文章详细介绍了连接泄露的排查过程、HikariCP的核心参数配置、监控指标设置以及防御性编程实践,帮助开发者避免类似问题并优化数据库连接管理。

weixin_26846533的博客 375

mysql长时间断开报错 spring_springboot jpa多数据源报错:HikariPool-2-Connection is not available,request timedout,S...

**业务需求:**需要从其他数据库中同步业务数据,以支持当前系统的数据需要**技术栈:**spring boot2.0框架 jpa mysql**问题描述:**第一次尝试多数据源的开发,在做定时任务同步数据时发现经常报错,错误信息在上面图片中,有的人说是连接池不够用了,有的说是配置问题,有的说是MySQL中有个wait time_out的配置8小时时间太短了于是我就一个一个去尝试1、连接池的问题,...

weixin_30579719的博客 1914

数据库连接池引起的FullGC问题,看我如何一步步排查、分析

Old Gen 从上图可以发现内存中存在长时间被引用,无法被YongGC所回收的对象,并且对象大小一直在增长。直到Old Gen被堆满之后触发Full GC后对象才会回收。 临时措施 现在问题已经找到了,到目前为止只是3台实例触发了FullGC,但是在查看其它实例内存使用情况时,发现基本上所有的实例Old Gen都快到达临界点了。所以临时解决方案是保留一台实例现场,滚动重启其它所有的实例,避免大量的实例同时进行FullGC。否则很可能导致服务雪崩。 原本服务是有设置jvm监控告警的,理论上来说当内存使.

m0_65485166的博客 1370

数据库连接异常: HikariPool-1 - Connection is not available, request timed out after 30000ms.

请求量超出数据库连接数据,提示数据库连接异常解决方案

m0_46286757的博客 2万+

Druid连接池超时问题排查:从内存快照到长SQL锁表的完整解决过程

本文深度剖析了Java微服务中Druid连接池超时导致服务不可用的静默故障。通过从JVM内存快照分析到数据库长SQL锁表排查的完整实战路径,提供了系统性诊断方法、关键参数调优方案及长效预防机制,帮助开发者彻底解决这一经典难题。

weixin_29280219的博客 655

[EDA系列]二、Altium Designer异形封装实战:从CAD导入到PCB布局

本文详细介绍了在Altium Designer中实现异形封装的实战流程。通过五步核心操作,将CAD软件中的复杂二维轮廓精准导入并转换为可直接用于PCB布局的智能封装,解决了不规则形状铺铜的难题,特别适用于射频天线、传感器外壳等对机械尺寸有严苛要求的设计场景。

weixin_29194817的博客 142

Spring Boot Connection is not available, request timed out after 30000ms问题排查解决

最近上线的项目凌晨出现了下图异常 因为以前从没碰到过这种情况,首先怀疑是hikari链接池配置问题。最后配置修改如下: spring.datasource.dynamic.datasource.master.type=com.zaxxer.hikari.HikariDataSource spring.datasource.dynamic.datasource.master.hikari.min-idle=5 spring.datasource.dynamic.datasource.master.hikar

wantLight的博客 3万+

Matlab中eig内置函数转为C语言

本文记录一下如何将MATLAB中的eig函数转为C语言,即通过C语言求解矩阵的特征值与特征向量。[V,D]=eig(Rx)中V为矩阵Rx的特征向量,D为矩阵的特征值。其中Rx维度为12*12的复矩阵。 首先在MATLAB端创建入口函数保存为eigvalue.m: 打开MATLAB Coder,添加入口函数: 3.在定义输入类型窗口中,需要添加输入数据来训练...

u011441044的博客 3515

一次达梦 DM8 连接池泄露排查:从“怀疑慢 SQL”到定位代码异常分支

一次典型的达梦 DM8 连接池泄露排查过程:系统压测时越跑越慢,最终连接池耗尽。最初误判为慢 SQL,随后通过观察连接池指标、排查事务边界和检查 JDBC 使用方式,最终定位到异常分支未释放连接的问题。

weixin_55511192的博客 857

NCCL使用指南-进阶篇

前文介绍了NCCL的常用环境变量,本文介绍了NCCL-test性能基准测试,以及一些大规模集群测试的经验数据。

father_yingying的博客 1405

超10万,两台Mac Studio在家就能跑满血DeepSeek,网友:这是性价比最高的大模型一体机

在AI计算领域,没有比这更强的个人电脑了。这要从它的架构说起。对于那些有本地部署满血版DeepSeek需求的用户,目前建议的配置是选购512GB统一内存 + 1TB SSD,搭载M3 Ultra芯片的Mac Studio,官网售价74249元,可以叠加国补、教育优惠、12期分期等,这可能是目前门槛最低、性价比最高的满血版DeepSeek本地部署方案。对于企业而言,尽管Mac Studio确实可以部署6000亿参数的大模型,但在内存带宽、模型精调服务等方面,跟专用的大模型一体机仍有差距,采购需要谨慎评估。

2501_90444774的博客 1914

如何避免JDBC池和内存溢出?优化策略大揭秘!

在这节课中,我们做了三个阶段的分析优化。在第一阶段中,我们修改了JDBC池,虽然TPS有上升的趋势,但是,新问题也同样出现了:TPS非常不稳定,还有断断续续的情况。在第二阶段中,我们分析了内存溢出的问题,定位出了原因并优化了内存问题。虽然我们在TPS曲线上明显看到了优化的效果,但仍然没有达到理想的程度。在第三阶段中,我们分析定位了SQL的问题,这是非常合乎逻辑的。因为我们在第二阶段中修改了SQL,所以到了第三阶段,就要直接到数据库中做相应的定位。从结果上看,效果不错,TPS已经有明显正常的趋势了。

JavaEdge全是干货的技术号 1908

《嵌入式最全面试题-Offer直通车》目录

嵌入式领域蓬勃发展,嵌入式工程师成为众多科技企业争抢的热门人才。如果你渴望在嵌入式面试中脱颖而出,成功斩获心仪的 offer,那么《嵌入式最全面试题 - Offer直通车》将是你的绝佳选择。本专栏是优快云是热门专栏,100多篇文章,总字数过百万。每月新增订阅用户过百,现在是优惠价9.9元,后面要逐渐恢复原价,早订阅早受益。本专栏精心整理了众多超万字的精华内容,总计达数十万字的嵌入式面试题总结。涵盖从嵌入式基础知识到各大厂面试真题,从驱动开发到操作系统,从硬件到软件等各个方面。

大模型大数据攻城狮的专栏 8389

JDBC连接泄露问题的排查过程总结

当前使用的Spring JDBC版本是5.0.0.RC1,HikariCP版本是3.1.0。 今天测试同学反馈在前端页面点击次数多了,就报500错误,数据显示不出来。于是我在后台服务日志中观察发现HikariCP连接池报如下的错误: getDataByWorkSheetId method Exception:HikariPool-2 - Connection is ...

weixin_30639719的博客 974

基于Simulink建模仿真的滑模控制的磁悬浮轴承稳定控制仿真

磁悬浮轴承(Magnetic Bearing)利用电磁力来支撑和定位转子,无需机械接触,因此在高速旋转设备中具有广泛应用。滑模控制(Sliding Mode Control, SMC)是一种鲁棒性强的非线性控制方法,适用于磁悬浮轴承的精确控制。以下是基于Simulink的磁悬浮轴承滑模控制系统的详细设计与仿真步骤。通过上述步骤,设计并实现了基于 Simulink 和 Control System Toolbox 的磁悬浮轴承滑模控制系统。

MHD0815的博客 778

2 硬件工程师笔面试高频知识考点真题解析——电容

本文全面解析了电容在电子电路中的关键应用与技术要点。主要内容包括:1. 电容选型核心要素:介质材质(陶瓷/电解/钽电容等)、容值精度、耐压等级、温度特性、ESR参数等,不同应用场景(滤波/去耦/谐振等)的选型策略。2. 典型电路应用原理:详细阐述去耦电容布局规则、晶振负载电容作用、共射放大电路旁路电容功能,以及RC电路的滤波/定时等应用。3. 特殊问题解决方案:MLCC啸叫机理与对策、寄生电容影响与消除、高速信号线电容使用禁忌等工程实践难题。4. 安全规范要点:X/Y电容的区别与选用、电解/钽电容防反接措施

XU157303764的博客 1557

记一次线上JVM原生系统内存泄露排查

目录问题报告应用概况初步分析Java堆内存,MetaSpace等使用情况Java堆外内存分析进程原生内存分析(Native Memory)原生内存详细分析内存内容分析引入jemallocjava.util.zip.Inflater.inflateBytes调用栈跟踪Kylin JDBC Driver内存泄露分析结论 问题报告 一日运维报告某应用JVM进程被OOM kill [日期] 10-15-1...

以简为道 4666

uniapp [全端兼容] - 实现全景图Vr 720°全景效果查看预览功能,3D全景图流畅不卡顿渲染+手势拖拽+悬浮工具按钮,uniAPP实现vr看720度全景效果示例代码(H5小程序APP全兼容)

uniapp显示720度全景图,720°全景图显示,在h5中展示720°全景图,浏览全景图,基于uniApp实现vr全景预览,加载全景图,uni-app全景预览插件,UNI-APP实现3D全景图,实现720°全景图展示,uniapp全景视频播放,uniapp项目实现vr720度全景图片预览,在网页上展示760全景图片和视频,全景图场景切换,UNIAPP全景VR图,uniapp加载720全景图_uniapp怎么加载vr图片,uniapp实现vr全景看房,uni-app实现全景效果,加载很慢卡怎么办,实现全景预

🏆 前端领域优质创作者 1万+

SpringBoot数据库连接泄露快速排查方法

快速排查SpringBoot Hikari数据库连接池连接泄露的方法,java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30000ms.

Daphnis的博客 2195

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

记一次jdbc泄漏与解决方案

大家好,我是入错行的bug猫。(http://blog.youkuaiyun.com/qq_41399429,谢绝转载) 这是一次非常非常非常脑蛋疼的debug经历 上周五bug猫请假外出。在路上收到公司的紧急电话,说是系统访问慢,各种地方报错。 初步判断是连接池满了,无法获取到Jdbc链接。已经重启过几次了,让bug猫抓紧解决! 当时bug猫身边仅一部手机,赶紧去网吧连远程公司电脑,然后上服务器一看系统的监...

bug猫的博客 1219

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

mysql连接池泄露_一次线上故障:数据库连接池泄露后的思考

一:初步排查早上作为能效平台系统的使用高峰期,系统负载通常比其它时间段更大一些,某个时间段会有大量用户登录。当天系统开始有用户报障,发布系统线上无法构建发布,然后后续有用户不能登录系统,系统发生假死,当然系统不是真的宕机,而是所有和数据库有关的连接都被阻塞,随后查看日志发现有大量报错。和数据库连接池相关:Caused by: org.springframework.jdbc.CannotGetJd...

weixin_39949776的博客 654

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

apache httpclient 连接池 工具_一次线上故障:数据库连接池泄露后的思考

一次线上故障:数据库连接池泄露后的思考一:初步排查早上作为能效平台系统的使用高峰期,系统负载通常比其它时间段更大一些,某个时间段会有大量用户登录。当天系统开始有用户报障,发布系统线上无法构建发布,然后后续有用户不能登录系统,系统发生假死,当然系统不是真的宕机,而是所有和数据库有关的连接都被阻塞,随后查看日志发现有大量报错。和数据库连接池相关:Caused by: org.springframewo...

weixin_39535752的博客 358

Java SQL异常深度解析:从Access Denied到连接泄露的排查与防御

在Java企业级应用开发中,数据库连接与SQL执行是核心环节,而java.sql.SQLException作为JDBC规范定义的根异常,是数据库交互健康状况的关键指标。其背后涉及连接管理、SQL执行、事务控制与资源释放等基本原理。理解其成因与处理机制,对于保障应用稳定性、数据一致性具有重要技术价值,尤其在微服务与高并发场景下更为关键。本文聚焦常见的“Access denied”认证异常与连接泄露问题,通过剖析连接池配置、SQL优化及事务边界等实践,提供从快速定位到根治解决的系统性方案,并结合HikariCP

weixin_30225755的博客 339

一次mysql数据库连接池泄露的解决经历

前言 最近用了公司某框架,部署到现场后,现场运维开始维护现场数据,在不断操作的过程中,系统崩溃,查看后台日志,druid连接池已经获取不到连接。于是开始了排查之旅。在此记录。 排查开始 首先后台的报错是这样的。 exception=org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: ### Error querying databas

经典鸡翅 2700
上一篇: IDEA 编译运行 Spring Boot 2.0 源码
下一篇: MySQL timeout调研与实测
Viking_bird
博客等级 码龄11年 92粉丝 183原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值