• go语言 Error 1040: Too many connections 最大连接数


    golang 数据库最大连接数的坑

    报错如下
    golang 版本 1.19

    Error 1040: Too many connections
    D:/GolandProjects/souti/src/main/mysql_conn.go:56 (0xe21d0f)
    DbQuery: panic(err)
    D:/GolandProjects/souti/src/main/aid_ctrl.go:19 (0xe20e15)
    initAidCtrl.func1: qListRes := Dbc.Query(“SELECT 马赛克 ORDER BY CONVERT(马赛克,SIGNED) LIMIT 5”, c.Param(“aid”))
    D:/GOPATH/pkg/mod/github.com/gin-gonic/gin@v1.8.1/context.go:173 (0xde7f81)
    (*Context).Next: c.handlersc.index
    D:/GOPATH/pkg/mod/github.com/gin-gonic/gin@v1.8.1/recovery.go:101 (0xde7f6c)
    CustomRecoveryWithWriter.func1: c.Next()
    D:/GOPATH/pkg/mod/github.com/gin-gonic/gin@v1.8.1/context.go:173 (0xde7086)
    (*Context).Next: c.handlersc.index
    D:/GOPATH/pkg/mod/github.com/gin-gonic/gin@v1.8.1/logger.go:240 (0xde7069)
    LoggerWithConfig.func1: c.Next()
    D:/GOPATH/pkg/mod/github.com/gin-gonic/gin@v1.8.1/context.go:173 (0xde6190)
    (*Context).Next: c.handlersc.index
    D:/GOPATH/pkg/mod/github.com/gin-gonic/gin@v1.8.1/gin.go:616 (0xde5df8)
    (*Engine).handleHTTPRequest: c.Next()
    D:/GOPATH/pkg/mod/github.com/gin-gonic/gin@v1.8.1/gin.go:572 (0xde593c)
    (*Engine).ServeHTTP: engine.handleHTTPRequest©
    D:/Go/src/net/http/server.go:2947 (0xc2616b)
    serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
    D:/Go/src/net/http/server.go:1991 (0xc21386)
    (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
    D:/Go/src/runtime/asm_amd64.s:1594 (0x9b6d20)
    goexit: BYTE $0x90 // NOP

    golang都吹出花来了,这也好,那也好,就是坑也不少

    我试了网上各种各样的方法,有说要手动Close连接的,下一条查询直接就会报错

    说结论吧:

    如果你查询的结果只有一条,不能用 Query 函数查询,需要使用 QueryRow 函数查询

    一切都因为我写了个骚操作

    我看着网上循环取数据的 demo 私自改装出了只取一条数据的代码

    //这是我参考的循环代码
    变量 := Dbc.Query("寻常的SQL语句", 参数) //查询
    for 变量.Next() {//我把它理解成了java中的 hasNext()方法
    	ele := 结构体{} //使用结构体接收数据
    	变量.Scan(&ele.Qid, &ele.Num, &ele.Name, &ele.Desc)//查询数据
    	eleList1 = append(eleList1, ele)//拼装数组
    }
    
    //然后我写出了这样的代码 注意,这里直接获取了数据而没有循环
    	变量 := Dbc.Query("只会返回一条数据的SQL语句", 参数) //查询
    	变量.Next()
    	变量.Scan(&e.属性)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    于是,当程序运行一段时间后,错误就发生了

    查询了一下这个问题,有说要调用 Ping 函数的,有说要 Close 的,我都尝试了,根本没用。

    在看到很多说 golang 泄露内存的内容后,我灵光一闪,可能问题就出在我改造的这条语句。

    于是我把他换成了 QueryRow 的方式调用,果然问题消失了。

    经过多次尝试后,下面这种写法不会造成内存泄漏

    变量 := Dbc.Query("只会返回一条数据的SQL语句", 参数) //查询
    变量.Next()				//第一次调用 Next
    变量.Scan(&e.属性)		//调用 Scan
    变量.Next()				//第二次调用 Next
    
    • 1
    • 2
    • 3
    • 4

    只有他,可以等同于

    //应该使用的形式
    变量 := Dbc.QueryRow("只会返回一条数据的SQL语句", 参数) //单行查询
    //只能换成这种形式
    变量 := Dbc.Query("只会返回一条数据的SQL语句", 参数) //多行查询
    变量.Next()				//第一次调用 Next
    变量.Scan(&e.属性)		//调用 Scan
    变量.Next()				//第二次调用 Next
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    于是我们可以得到结论:

    golang 数据库操作中,QueryRow 函数不会造成内存(指连接池资源)泄漏,但是 Query 函数有可能,你必须要使用循环去读取 Query 的结果,才不会导致泄漏,如果你自作聪明,对只返回一条语句的查询使用 Query 而非 QueryRow,golang 将会教你做人。除非,你可以完美的骗过 golang 假装你是个循环,这块内容的底层就是为 for i 循环设计的(for range 也不例外)。可行的绕过方式是先判断 Next() 然后执行 然后再判断 Next() 。在这个过程中 Next() 函数需要被调用两次,就像for循环中的条件那样,如此才不会引发问题。

  • 相关阅读:
    使用frp+nginx内网穿透并配置https
    react 高效高质量搭建后台系统 系列 —— 前端权限
    Github爆火,阿里内部疯传的中间件核心原理与实践笔记终于开源
    37. 解数独
    Https协议原理剖析【计算机网络】【三种加密方法 | CA证书 】
    http相关配置梳理
    【python】实现k-means
    流量录制回放工具jvm-sandbox-repeater入门篇——录制和回放
    java项目-第155期ssm班级同学录网站-java毕业设计_计算机毕业设计
    Avalonia 实现跨平台的视频聊天、屏幕分享(源码,支持Win、银河麒麟、统信UOS)
  • 原文地址:https://blog.csdn.net/weixin_43074462/article/details/127797471