Golang MySQL错误 - packets.go:33:意外的EOF

8

我正在将整个代码库从PHP切换到Go,在运行几个进程时,我会随机地遇到这个错误:

[mysql] 2016/10/11 09:17:16 packets.go:33: unexpected EOF

这是我的数据库包,用于处理所有与数据库的连接:
package db

import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
    "pkg/db"
)

var connection *sql.DB
var err error

func GetConnection() *sql.DB {
    if connection != nil {
        fmt.Println("********** CHECKING PING")
        err = connection.Ping()
        if err == nil {
            fmt.Println("************ CONNECTION STILL ACTIVE")
            return connection
        } else {
            fmt.Println("********** PING ERROR: " + err.Error())
        }
    }

    connection, err = sql.Open("mysql", db.DEVUSER + ":" + db.DEVUSER_PASSWORD + "@tcp(localhost:3306)/main?parseTime=true")
    if err != nil {
        panic(err)
    }

    return connection
}

这个db包出错的原因是我做错了什么?这个错误具体意味着什么?我会确保如果有一个连接已经打开,就返回当前连接,所以对于多个请求它使用相同的连接对象。
以下是mysql packets.go的节选:
// Read packet to buffer 'data'
func (mc *mysqlConn) readPacket() ([]byte, error) {
    var payload []byte
    for {
        // Read packet header
        data, err := mc.buf.readNext(4)
        if err != nil {
            errLog.Print(err)
            mc.Close()
            return nil, driver.ErrBadConn
        }

        // Packet Length [24 bit]
        pktLen := int(uint32(data[0]) | uint32(data[1])<<8 | uint32(data[2])<<16)

        if pktLen < 1 {
            errLog.Print(ErrMalformPkt)
            mc.Close()
            return nil, driver.ErrBadConn
        }

        // Check Packet Sync [8 bit]
        if data[3] != mc.sequence {
            if data[3] > mc.sequence {
                return nil, ErrPktSyncMul
            }
            return nil, ErrPktSync
        }
        mc.sequence++

        // Read packet body [pktLen bytes]
        data, err = mc.buf.readNext(pktLen)
        if err != nil {
            errLog.Print(err)
            mc.Close()
            return nil, driver.ErrBadConn
        }

        isLastPacket := (pktLen < maxPacketSize)

        // Zero allocations for non-splitting packets
        if isLastPacket && payload == nil {
            return data, nil
        }

        payload = append(payload, data...)

        if isLastPacket {
            return payload, nil
        }
    }
}

第一个"errLog.Print(err)"在“读取数据包头”部分的第33行。

非常感谢您的帮助!

我在连接程序中添加了一些log.Println,并让进程运行,在我遇到这个错误的地方,控制台会打印出以下内容:

********** CHECKING PING
************ CONNECTION STILL ACTIVE
[mysql] 2016/10/11 11:57:27 packets.go:33: unexpected EOF
********** CHECKING PING
************ CONNECTION STILL ACTIVE

1
你所打印的错误信息是 packets.go:33: unexpected EOF,请问在 packets.go 文件中第 33 行是什么? - JimB
1
错误的源头不在您发布的代码中,但是GetConnection从未为全局变量connection分配值。这是否应该这样做? - JimB
我不知道"mc.buf.readNext"是什么。那不是我的代码,它在mysql包中。 - jrkt
看看我的修改。这样行吗?使用connection.Ping()检查连接是否仍然存在,如果抛出错误,则重置连接。 - jrkt
1
你尝试过将空闲连接数设置为0吗? - jrkt
显示剩余11条评论
4个回答

5
看起来Github问题提供了解决方法。对于我的情况,解决方法是将MaxIdleConnections设置为0。我已经让服务器运行了24小时,在几个小时内反复查询,但仍未出现错误。

感谢@city提供的链接。


我也遇到了同样的错误,但是将 MaxIdleConnections 设为 0 对我没有起作用。参考链接:https://dev59.com/x6bja4cB1Zd3GeqPn-2H - Naresh
3
我们目前最好的解决方案是禁用连接池?我对此不太满意。一旦我找到更好的解决方案,我会进行更新。 - TaoJS

1
import (
    "database/sql"
    "time"
)
//..snip...
db, err = sql.Open("mysql", url)
db.SetConnMaxLifetime(time.Minute * 4) // <-- this

它对我有帮助。解释:这里

1
func parent() {
conn, err := db.ClientCat.Conn(ctx)
if err != nil {
    return nil, customError.MySqlConnectionError(ctx, errors.New("Connection_not_Established"))
}
//execute some query
defer conn.Close() //*******this won't close until child() finishes
child()

}

func child() {
//under high traffic it won't get connection as they are taken by parent method
//usually we have 10,20,100 etc.. connections available as per configuration, under high traffic all will be taken by parent
conn, err := db.ClientCat.Conn(ctx)
if err != nil {
    return nil, customError.MySqlConnectionError(ctx, errors.New("Connection_not_Established"))
}
//execute some query
defer conn.Close()

这种情况也可能发生在上述场景中,请进行验证。 如果系统负载过高并且我们收到了数百个请求,则可能会出现此问题。

基本上,每次请求要在子方法中建立连接时,它都会等待很长时间,然后由于连接被父方法占用而超时。

同时,父方法不会结束直到子方法完成。但是子方法将等待连接。因此,一旦我们的父方法已经建立的连接数=最大连接数,即使在父方法中,它也可能开始无法获取下一个请求的连接。


0

DSN 添加了 net_write_timeout 选项

root:root@tcp(localhost:3306)/prod?net_write_timeout=6000

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接