如何确保查询在其上下文被取消时被终止?

问题描述 投票:0回答:1

我最近了解到 Go 的 mysql 驱动程序不会在上下文取消时终止正在运行的查询。这是一个问题,因为我的应用程序可以生成锁定数据库的长时间运行的查询(这是它自己的问题,但不是我现在关注的问题)。我想确保如果请求被取消,来自该请求的任何正在运行的查询都会被终止。

我一直在使用这个功能:

/*
GetConn() returns a connection to the database. It also launches a goroutine
that kills any running queries when the connection is closed.
*/
func GetConn(ctx context.Context) (*sqlx.Conn, error) {
    conn, err := db.Connx(ctx)
    if err != nil {
        return nil, err
    }
    var connId int64
    if err := conn.GetContext(ctx, &connId, `SELECT CONNECTION_ID()`); err != nil {
        return nil, err
    }
    go func() {
        // Wait for the context to be canceled, and kill the connection
        select {
        case <-ctx.Done():
            if err := conn.Close(); err != sql.ErrConnDone {
                db.Exec("KILL ?", connId)
            }
        }
    }()

    return conn, nil
}

这可行,但我担心的是,如果调用者永远不会取消上下文怎么办? Goroutine 将永远等待。我对上下文和渠道不熟悉,所以我缺少什么吗?或者是否有更好的方法来确保请求中止时查询被终止?

mysql go sqlx
1个回答
0
投票

事实上,

KILL
也并没有真正终止查询。并不像想象的那样。它不会立即中断查询。它只是设置一个标志,表明查询“应该”被终止,并且由 MySQL 服务器最终注意到这个标志,并在那时终止查询。

https://dev.mysql.com/doc/refman/8.0/en/kill.html

说:

当您使用 KILL 时,会为线程设置一个特定于线程的终止标志。在大多数情况下,线程可能需要一些时间才能终止,因为仅在特定时间间隔检查终止标志:

请参阅该手册页,了解 MySQL 检查标志的特定时间列表。

在实践中,这在大多数情况下都是有效的。但我见过这样的情况:查询执行陷入某种模式,其中一项检查需要很长时间(如果有的话)才能发生。我不得不在操作系统级别强制重新启动

mysqld

服务才能最终终止查询。

所以不,没有 100% 保证的方法可以在上下文关闭时终止查询。

© www.soinside.com 2019 - 2024. All rights reserved.