首页 > 数据库 >记录一次解决数据库连接池连接泄露BUG

记录一次解决数据库连接池连接泄露BUG

时间:2023-08-10 14:12:13浏览次数:47  
标签:java 数据库 druid springframework DruidDataSource org com BUG 连接池

1 BUG现象

系统并发请求,系统停滞无法使用,所有接口都是无法与后端进行交互的状态,系统并没有宕机

2 BUG的业务流程

  1. 插入分数方法 涉及插入表ABCD 加了声明式事务
  2. 查询分数方法 涉及表ABCD
controller() {
	@Transactional
	insertVo();
	selectById();
}

3 排查原因

因为代码不是我写的,一开始我就是怀疑是死锁导致的BUG,然后我用Jconsole,去检测一下死锁,并没有发现死锁,接下来我去Mysql看有没有死锁,结果也没有发现,然后我就懵了,jvm没有锁,mysql也没有锁且没有SQL在执行,为什么请求就会全注阻塞?

然后我去开始去看这个代码了,我发现他在控制层调用了两个业务层,通常我们只在控制层去做校验去调用一个service啊,然后我就继续看,insertVo插入了很多查询了很多,耗时3秒钟左右,selectById查询了一条SQL,这两个明面上的代码并没有什么加锁或什么飞天操作,想了半天搞不懂为什么。

然后我开始用排除法,把这些代码一一注释调试一下。我把insertVo注释掉,这个毋庸置疑,那只有一个简单的操作了,就查一表返回,这个绝对是没问题的,然后我把selectById注释掉,居然就好了?,selectById只有一条查询SQL啊也没有加锁,这个能解决但是肯定也不是这个原因。

然后我用druid监控到可使用连接数一直在占用,没有释放,我就去查druid配置,发现配置了

initial-size: 20 #初始大小
min-idle: 20 #最小空闲
max-active: 40 #最大链接
max-wait: 10000 #配置获取连接等待超时的时间

这个配置也没有毛病啊,没办法了我只能去看线程的具体信息了,查出来所有的线程池连接线程都是这样的

"pool-6-thread-10" #244 prio=5 os_prio=31 tid=0x00007fe94235f000 nid=0x22803 waiting on condition [0x00000003150ce000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x00000006c109e090> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
	at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
	at com.alibaba.druid.pool.DruidDataSource.takeLast(DruidDataSource.java:2315)
	at com.alibaba.druid.pool.DruidDataSource.getConnectionInternal(DruidDataSource.java:1781)
	at com.alibaba.druid.pool.DruidDataSource.getConnectionDirect(DruidDataSource.java:1494)
	at com.alibaba.druid.filter.FilterChainImpl.dataSource_connect(FilterChainImpl.java:5058)
	at com.alibaba.druid.filter.stat.StatFilter.dataSource_getConnection(StatFilter.java:704)
	at com.alibaba.druid.filter.FilterChainImpl.dataSource_connect(FilterChainImpl.java:5054)
	at com.alibaba.druid.filter.FilterAdapter.dataSource_getConnection(FilterAdapter.java:2759)
	at com.alibaba.druid.filter.FilterChainImpl.dataSource_connect(FilterChainImpl.java:5054)
	at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:1469)
	at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:1459)
	at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:83)
	at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122)
	at org.hibernate.internal.NonContextualJdbcConnectionAccess.obtainConnection(NonContextualJdbcConnectionAccess.java:38)
	at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.acquireConnectionIfNeeded(LogicalConnectionManagedImpl.java:104)
	at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getPhysicalConnection(LogicalConnectionManagedImpl.java:134)
	at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getConnectionForTransactionManagement(LogicalConnectionManagedImpl.java:250)
	at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.begin(LogicalConnectionManagedImpl.java:258)
	at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.begin(JdbcResourceLocalTransactionCoordinatorImpl.java:246)
	at org.hibernate.engine.transaction.internal.TransactionImpl.begin(TransactionImpl.java:83)
	at org.springframework.orm.jpa.vendor.HibernateJpaDialect.beginTransaction(HibernateJpaDialect.java:184)
	at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:402)
	at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:376)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:572)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:360)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:99)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
	at com.treach.platform.modules.service.impl.SysLogService$$EnhancerBySpringCGLIB$$36a85251.insert(<generated>)
	at com.treach.platform.log.factory.LogTaskFactory$2.run(LogTaskFactory.java:56)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:750)

   Locked ownable synchronizers:
	- <0x00000007741f0d68> (a java.util.concurrent.ThreadPoolExecutor$Worker)

是的,连接池连接一直被占用锁住了,为什么会被锁住呢?,也设置了连接等待超时时间啊,然后我怀疑是配置没有生效,写了个代码看看

public static void main(String[] args) throws SQLException {
        ConfigurableApplicationContext run = SpringApplication.run(NdCyApplication.class, args);
        DruidDataSource bean = run.getBean(DruidDataSource.class);

        int maxActive = bean.getMaxActive();
        long maxWait = bean.getMaxWait();
        log.info("数据库线程池与数据库最大链接数" + String.valueOf(maxActive));
        log.info("数据库线程池等待链接数超时时间"+String.valueOf(maxWait));
    }

结果:

数据库线程池与数据库最大链接数8
数据库线程池等待链接数超时时间-1

这个和配置的不一样啊,真的没有生效,然后我又去查为什么没有生效,原来配置类里面有个DataSoure

@Bean     //声明其为Bean实例
@Primary  //在同样的DataSource中,首先使用被标注的DataSource
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource dataSource(){
        DruidDataSource datasource = new DruidDataSource();
        List<Filter> filters = new ArrayList<>();
        filters.add(wallFilter);
        filters.add(new StatFilter());
        datasource.setProxyFilters(filters);
        return datasource;
}

我们applcation.yaml的配置被覆盖了,druid默认等待链接数超时时间-1,难怪长时间占用连接没有超时。

4 解决

把等待连接超时时间等设置上

@Bean     //声明其为Bean实例
@Primary  //在同样的DataSource中,首先使用被标注的DataSource
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource dataSource(){
        DruidDataSource datasource = new DruidDataSource();
        datasource.setInitialSize(20);
        datasource.setMaxActive(80);
        datasource.setMaxWait(5000);
        List<Filter> filters = new ArrayList<>();
        filters.add(wallFilter);
        filters.add(new StatFilter());
        datasource.setProxyFilters(filters);
        return datasource;
}

成功

5 不懂的点

为什么会出现不回收线程的情况 按理来说现在没有SQL在执行,连接数不是会被回收吗 回到线程池 等待的线程就有连接了 就能不卡死了 为什么呢?

标签:java,数据库,druid,springframework,DruidDataSource,org,com,BUG,连接池
From: https://www.cnblogs.com/isyues/p/17620185.html

相关文章

  • 耗时6个月,我做了一款干净、免费、开源的AI数据库
    一、Chat2DB简介在消失的这段时间,我和小伙伴们做了一款集成了AI的数据库管理工具Chat2DB。他是数据库也集成了AIGC的能力,能够将自然语言转换为SQL,也可以将SQL转换为自然语言,还可以给出SQL的优化建议,可以极大提升效率。GitHub地址:https://github.com/chat2db/chat2db官网地址:ht......
  • 数据结构与数据库选型:构建高效业务系统的关键要素
    数据结构与数据库选型:构建高效业务系统的关键要素构建高效业务系统的关键要素之一是选择合适的数据结构和数据库。下面是一些关于数据结构和数据库选型的考虑因素:1.数据结构:-选择最适合业务需求的数据结构是非常重要的。常见的数据结构包括数组、链表、栈、队列、哈希表、......
  • MYSQL数据库 学习大全
    MYSQL数据库目前广泛的应用在各种个人、商务系统中,各种技术都比较成熟。把自己学习的一些过程总结一下,该文章设计到的内容都没有做太具体的阐述,只是一个简单的入门手册,假如想看更多内容可以参看MYSQL的联机手册。1MYSQL安装先下载安装包:mysql-5.0.27-win32.zipmysq......
  • MYSQL数据库知识点
    CONCAT()函数的使用方法--双列合并SELECTCONCAT(id,'@',number2)FROMtable1--多列合并SELECTCONCAT(id,'AA',number,'B',number2)FROMtable1table1的数据以及拼接后的效果  DATE_FORMAT()时间格式化函数 ......
  • Microsoft SqlServer数据库备份出现操作系统错误 5(拒绝访问。)
    备份对于服务器“ECS-133509\SQLEXPRESS”失败。 (Microsoft.SqlServer.SmoExtended)System.Data.SqlClient.SqlError:无法打开备份设备'C:\555548885455.bak'。出现操作系统错误5(拒绝访问。)。(Microsoft.SqlServer.Smo)解决办法:1、不能将备份文件放在根目录下,......
  • MySQL 之【视图】【触发器】【存储过程】【函数】【事物】【数据库锁】【数据库备份】
    一.多表联合查询 创建表和数据#多表查询语法select字段1,字段2...from表1,表2...[where条件]注意:如果不加条件直接进行查询,则会出现以下效果,这种结果我们称之为 笛卡尔乘积#查询人员和部门所有信息select*fromperson,dept笛卡尔乘积公式:A表中数据条数  *......
  • MySQL数据库笔记(一)
    第一章数据库概述1、什么是数据库数据库是一种存储并管理数据的软件系统存储:持久化管理:增删改查常用的存储数据的方式:1、Java中的变量:生命周期短,不能实现持久化[内存]2、序列化:管理数据时依赖于Java中的反序列化[硬盘]3、txt,办公软件:没有统一的方式管理数据[硬盘]4......
  • Apache DolphinScheduler 3.1.8 版本发布,修复 SeaTunnel 相关 Bug
    近日,ApacheDolphinScheduler发布了3.1.8版本。此版本主要基于3.1.7版本进行了bug修复,共计修复16个bug,1个doc,2个chore。其中修复了以下几个较为重要的问题:修复在构建SeaTunnel任务节点的参数时错误的判断条件修复SeaTunnel任务运行模式默认为运行,无......
  • whistle修改接口返回步骤(只影响前端展示,不会插入数据到数据库)
    一、安装node、whistle安装教程:http://wproxy.org/whistle/install.html二、抓包/修改接口返回手机端抓包/修改接口返回步骤与web端类似。Web端抓包/修改接口返回1、下载证书启动whistle:在控制台中输入w2start即可启动whistle。点击whistle页面菜单中的HTTPS,点击二维码,即可下载......
  • 在使用时序数据库 TDengine 进行 SQL 查询时,这些问题需要注意
    小T导读:尽管时序数据处理的特点是以写操作为主,读操作为辅,但查询需求也不容忽视。为方便用户上手,时序数据库(TimeSeriesDatabase)TDengine 采用SQL作为查询语言,主要查询功能包括单列及多列数据查询、数值列及聚合结果的四则运算、时间戳对齐的连接查询操作等,本文将就部分查询......