翔云

Just try, don't shy. 最新文章请点击
随笔 - 294, 文章 - 0, 评论 - 27, 阅读 - 49万
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

在使用golang 连接 mysql时,为了节省连接资源,在连接使用过后,希望在指定长度时间不再使用后,自动关闭连接。
这时,经常会使用SetConnMaxLifetime(),设置最大连接有效时间,
使用SetConnMaxIdleTime(),设置最大空闲连接时间 max idle time。

这两个函数的作用听起来差不多,理论上,都能达到相同效果。
但是在实际使用中,却有些出人意料。

首先看下测试代码,在以下代码中,
设置 max idle time 为传入的参数值,
设置 max life time 为传入的参数值,
设置 max open conn 为1,
设置 max idle conn 为1

package main

import (
	"database/sql"
	"log"
	"fmt"
	"os"
	"strconv"
	"time"
	
	_ "github.com/go-sql-driver/mysql"
)

var dataBase = "root:xxxx@tcp(127.0.0.1:3306)/mysql?timeout=2s&readTimeout=6s&interpolateParams=true"

func getVar(name string) int {
	val := os.Getenv(name)
	if len(val) == 0 {
		panic(fmt.Sprintf("error getting: %v", name))
	}
	v, err := strconv.Atoi(val)
	if err != nil {
		panic(fmt.Sprintf("error parsing %v %v", name, err))
	}
	return v
}



func main() {
	db, err :=sql.Open("mysql", dataBase)  // connect to the db of your choice.
	if err != nil {
		panic(err)
	}
	defer db.Close()
	db.SetConnMaxIdleTime(time.Second * time.Duration(getVar("MAXIDLE")))
	db.SetConnMaxLifetime(time.Second * time.Duration(getVar("MAXLIFE")))
	db.SetMaxIdleConns(1)
	db.SetMaxOpenConns(1)
	sleep := time.Second*time.Duration(getVar("SLEEP"))
	for i := 0; i < 10; i++ {
		err = db.Ping()
		if err != nil {
            log.Fatalln("ping db fail:", err)
        }
		time.Sleep(sleep)
		print("\r", i)
	}
	fmt.Printf("\n%+v\n", db.Stats())
}

测试1

MAXIDLE=1 MAXLIFE=0 SLEEP=5 go run .

设置 max idle time 为1s,设置max life time为0s,也就是永不过期,相当于不设置life time。
每次连接之后,sleep 5s。

预期结果,循环10次,每次都会打开一个新的连接,旧的连接由于idle time到期而自动关闭。

go 1.15.15

output

9
{MaxOpenConnections:1 OpenConnections:1 InUse:0 Idle:1 WaitCount:0 WaitDuration:0s MaxIdleClosed:0 MaxIdleTimeClosed:0 MaxLifetimeClosed:0}

实际结果,只新建了一个连接,一直在使用,没有关闭连接。
也就是说设置max idle time 并没有生效。

go 1.17.12

9
{MaxOpenConnections:1 OpenConnections:0 InUse:0 Idle:0 WaitCount:0 WaitDuration:0s MaxIdleClosed:0 MaxIdleTimeClosed:10 MaxLifetimeClosed:0}

实际结果与预期相符。

测试2

MAXIDLE=1 MAXLIFE=2 SLEEP=5 go run .

设置 max idle time 为1s,设置max life time为2s,也就是idle time先到期
每次连接之后,sleep 5s。

预期结果,循环10次,每次都会打开一个新的连接,旧的连接是由于idle time到期自动关闭。

go 1.15.15

output

9
{MaxOpenConnections:1 OpenConnections:0 InUse:0 Idle:0 WaitCount:0 WaitDuration:0s MaxIdleClosed:0 MaxIdleTimeClosed:10 MaxLifetimeClosed:0}

实际结果与预期相符。

go 1.17.12

output

9
{MaxOpenConnections:1 OpenConnections:0 InUse:0 Idle:0 WaitCount:0 WaitDuration:0s MaxIdleClosed:0 MaxIdleTimeClosed:10 MaxLifetimeClosed:0}

实际结果与预期相符。

总结下,汇总以上测试结果如下表所示:

go版本 是否 max idle time 是否max life time 空闲连接回收是否生效
go 1.15.15 Y N N
go 1.15.15 Y Y Y
go 1.17.12 Y N Y
go 1.17.12 Y Y Y

在 go 1.15.15版本 或者其他相近版本中,只设置max idle time,不能自动回收空闲连接。

具体原因,可以参见 issue,或者具体查看go 源码,这应该是一个bug。

参考

database/sql: SetConnMaxIdleTime without SetConnMaxLifetime has no effect #41114

golang mysql 如何设置最大连接数和最大空闲连接数

相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示