Go数据库线程池操作问题
最近在使用go语言操作数据库的时候遇到个隐藏的问题,这种问题很难定位,最后经过多方测试、尝试、猜测最后才确认问题,问题是这样的:
当时我们当时用的go的gin框架做后台服务、使用mysql作为后台数据库,然后在初始化的时候设置了go数据库操作线程池,这个线程池是go语言自带的线程池,我们只需要设置一些参数就可以实现数据库线程池。然后最后测试测出来不知道什么原因,经过一段时间的测试,服务卡死了,所有的访问都无法正常访问;最开始是找路由框架的问题,找了半天也没找到问题,后面又猜测是非法字符操作的问题,最后经过各种测试发现是功能函数里面有个系统函数没用对,导致线程池到达上限,所有访问卡死。具体的导致原因和解决方法如下所示:
我们在线程池设置的地方是这样设置的:
const (dbMaxLiftTime = 2 * time.HourdbMaxIdleConns = 30dbMaxOpenConns = 100
)G_dbpap, err := sql.Open("mysql", mysqlurl)
if err != nil {golog.Error(err)return err
}
G_dbpap.SetMaxIdleConns(dbMaxIdleConns) //连接池的空闲数大小
G_dbpap.SetMaxOpenConns(dbMaxOpenConns) //设置最大打开连接数
G_dbpap.SetConnMaxLifetime(dbMaxLiftTime) //设置连接的最大生存时间
上面的代码中,我们打开了一个G_dbpap的全局操作mysql数据库的变量,然后我们设置了线程池,最大打开访问连接数为100,这个设置是导致我出现问题的关键,另外两个根据字面上的意思也能理解,记住这个100
然后我代码中有个API接口函数是这样写的:
sql_cmd := `DELETE FROM TABLEDATA`
_,err := G_dbpap.Query(sql_cmd)
if err != nil{return err
}
注意这个G_dbpap.Query,我看了他函数源码里面他的第一个返回值是Rows指针,下面附上了源代码
func (db *DB) Query(query string, args ...any) (*Rows, error) {return db.QueryContext(context.Background(), query, args...)
}
我之前也看了很多资料知道这个rows返回值用完必须要手动close,但是就是因为这个地方我图方便,因为是删除语句,我不需要处理返回值就用了下划线略过返回值,其实是有问题的,这个rows不close的话,这一次的请求线程就会一直占用,不会释放,所以接口测试超过100次,这个线程占用就会达到100次,然后上面设置的线程池最大连接数就是100次,所以就导致100次的接口测试后,所有使用G_dbpap句柄操作数据库的访问请求都会卡死。因为设置了最大线程池大小,达到最大后,访问请求就会等到之前的线程释放掉才会响应。
当时的心情真的很激动,折磨好久的问题终于定位到原因,然后怎么解决呢,两种方法:
1、像上面那种数据库操作请求,因为不需要返回值,所有只需将Query换成Exec执行数据库即可,如下所示
sql_cmd := `DELETE FROM TABLEDATA`
_,err := G_dbpap.Exec(sql_cmd)
if err != nil{return err
}
2、如果不像上面的那种,需要处理返回值的数据库操作,如select的,需要再使用完rows后close掉,如下所示
sql_cmd := `SELECT * FROM TABLEDATA`
rows,err := G_dbpap.Query(sql_cmd)
if err != nil{return err
}for rows.Next() {//获取rows的返回值操作}rows.Close()
这样用完操作然后Close掉才不会出现问题。
备注:从上面的情况来看,其实出现原因也是我自己的问题,删除操作数据库的操作函数不该用Query函数,但是其实我也非常感谢我用错,不用错,我就不会深刻理解用了Query没有Close会导致什么严重的后果。还有就是有人或许会说,如果数据库线程池操作那个不设置那100的限制,应该也不会出现这个问题,其实大家再仔细想想,如果前面没有设置那100的限制(好像默认是无上限),那么最后出现问题可能是灾难性的,设想没有释放的线程越来越多,最后导致系统崩了,到那时可能定位问题更是艰难无比了。
以上就是我此次遇到的问题和解决方法,记录于此,希望对后面的朋友有所帮助。
Go数据库线程池操作问题相关推荐
- Android官方开发文档Training系列课程中文版:线程执行操作之线程池操作
原文地址:http://android.xsoftlab.net/training/multiple-threads/run-code.html#StopThread 上节课我们学习了如何定义一个类用 ...
- c语言数据库线程池,C语言多线程中运行线程池,在线程池中运行线程池,,传递的结构体参数值为空/NULL/0...
typedef struct { }LoanInfos; typedef struct{ int cp;//主线程编号 int thread;//线程编号 long int time; int arr ...
- python线程池操作_python线程池和进程池
线程池和进程池 开局来张图 使用线程池的好处 1.提升性能:因为减去了大量新建.终止线程的开销,重用了线程资源 2.使用场景:适合处理突发性大量请求或需要大量线程完成任务.但实际任务处理时间较短 3. ...
- python线程池操作_Python mutiprocessing多线程池pool操作示例
本文实例讲述了Python mutiprocessing多线程池pool操作.分享给大家供大家参考,具体如下: python - mutiprocessing 多线程 pool 脚本代码: root@ ...
- 厚积薄发,丰富的公用类库积累,助你高效进行系统开发(11)---各种线程相关操作类...
俗话说,一个好汉十个帮,众人拾柴火焰高等都说明一个道理,有更多的资源,更丰富的积累,都是助你走向成功,走向顶峰的推动力. 本篇的公用类库的介绍主题是程序开发中多线程操作环境中,常用到的线程相关类,本篇 ...
- Java并发编程-ThreadPool线程池
ThreadPool线程池 1.线程池的优势 1.1.引言 1.2.为什么要使用线程池 2.线程池的使用 2.1.架构说明 2.2.线程池的三大方法 2.2.1.newFixedThreadPool( ...
- JUC探险-17、线程池
文章目录 一.线程: ①线程的创建 如果同时继承了Thread类且实现了Runnable接口,会怎样执行? ②线程状态 ③线程状态的转换 线程状态的转换操作 1 ...
- 线程池介绍:ThreadPoolExecutor
线程池介绍:ThreadPoolExecutor 线程池介绍 多线程技术的不足之处(需要线程池的原因) 什么是线程池 线程池的优势 线程池的架构 线程池的执行原理 线程池状态 任务提交内部原理 exe ...
- ExecutorService线程池
ExecutorService 建立多线程的步骤: 1.定义线程类 class Handler implements Runnable{ } 2.建立ExecutorService线程池 Execut ...
最新文章
- Journey源码分析三:模板编译
- 【Python-ML】SKlearn库性能指标-混淆矩阵和F1
- JAVA多线程--Thinking in java
- 流控组件Sentinel核心注解@SentinelResource中的参数fallback和blockHandler的使用方式
- matlab中关于程序运行的快捷键
- python如何进行web开发_如何用Python做Web开发
- 1.1、推断和设置“是否为 Web 环境”
- JAVA学习经验--总结JAVA抽象类和接口
- 如何让ARM板开机启动Qt
- 解方程计算器,一款数学神器APP,有需要的自己收藏!
- STM32CubeMX | STM32F1系列HAL库读写内部FLASH
- pytorch基础---李博文记录索引
- 苹果主屏幕按钮怎么设置_苹果手机屏幕横屏怎么调
- Preparatory Class-Day8------函数
- IDEA 一直卡在Buil(编译 write classes)报错资源不足
- 从零构建通讯器--7.1过往总结和心跳包代码实战
- Terracotta 3.2.1简介 (二)
- 二维码编码库qrencode
- 关于 CC BY-SA 4.0
- 基于数字温度传感器的数字温度计 华氏度和摄氏度