我用这么简单的代码遇到了一些奇怪的情况:
func InitDatabase(dataSourceName string) {
var err error
DBCon, err = sql.Open("mysql", dataSourceName)
if err != nil {
log.Panic(err)
}
log.Println("Ping...")
if err = DBCon.Ping(); err != nil { // <- it hangs here
log.Println(":(")
}
log.Println(":)")
}
我调试并发现它在此行中锁定了goroutine(fd_poll_runtime.go,第85行),看起来甚至没有连接:
res := runtime_pollWait(pd.runtimeCtx, mode)
它可以在这里等待多年,我的mac变得非常热。
我做了一个小改动:
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
if err = DBCon.PingContext(ctx); err != nil {
log.Println(":(")
}
log.Println(":)")
它仍然挂起,超时不起作用。
问题是,它在昨天工作了(而且,有趣的是,它适用于我朋友的机器,相同的参数),现在它甚至在重新启动后和重新安装mysql之后都没有(在终端/ goland / mysqlworkbench中完美运行)。
转到版本1.9,mysql驱动程序:“github.com/go-sql-driver/mysql”,mysql版本:5.7.20 Homebrew,macos版本:High Sierra 10.13.1,我在localhost上托管mysql,端口3306。
更新
终于奏效了。我将init代码复制到了干净的项目,并在那里工作。我开始注释掉代码,找出问题所在。我发现我在导入的包中有这个代码。即使这个包中的代码在数据库ping之后执行,但init代码之前执行并且以某种方式阻止了db.Ping()
:
func init() {
for i := 1; i <= maxWorkers; i++ {
go func(i int) {
for {
select {
case j, ok := <-jobs:
if ok {
j.invoke()
} else {
// loop
}
default:
// loop
}
}
}(i)
}
}
我重写了方法名称,并在数据库ping之后执行它,一切正常。
我不知道为什么会这样,但如果你有答案,可以随意发布。