取消正在进行中的数据库操作

本文翻译自《Canceling in-progress operations》。 你可以使用Go的context.Context管理正在进行中的操作。Context是一个标准的Go类型,可用来报告它所代表的整体操作是否已被取消并且不再需要。通过在你的应用程序中跨函数或服务传递context.Context,可以提前停止工作并返回一个错误。有关Context的更多信息,请参阅Go并发模式:Context

例如,你可能希望:

  • 结束长时间运行的操作,包括耗时过长的数据库操作。
  • 传播来自其他地方的“取消继续工作”请求,例如当客户端关闭连接时。

Go的许多API都采用Context参数,使你更容易在整个应用程序中使用Context

超时后取消正在进行中的数据库操作

你可以使用Context来设置超时时间或截止时间,在此之后操作将被取消。要派生具有超时时间或截止时间的Context,请调用Context.WithTimeoutContext.WithDeadline函数。

以下示例中的代码派生一个附带超时时间的Context,并将其传递到sql.DBQueryContext方法中。

func QueryWithTimeout(ctx context.Context) {
    // 创建一个附带超时时间的Context。
    queryCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
    defer cancel()

    // 传入这个附带超时时间的Context和一个查询语句。
    rows, err := db.QueryContext(queryCtx, "SELECT * FROM album")
    if err != nil {
        log.Fatal(err)
    }
    defer rows.Close()

    // 处理返回的行数据。
}

当一个context从外部的context派生而来时,由于queryCtx在本例中是从函数参数ctx派生的,如果外部的context被取消,那么派生的context也会自动取消。例如,在HTTP服务器中,HTTP.Request.Context方法返回与请求相关联的context。如果HTTP客户端断开连接或取消HTTP请求(可能使用HTTP/2),则该context将被取消。如果整个HTTP请求被取消,或者查询耗时超过五秒,那么将HTTP请求的context传递给上面的QueryWithTimeout函数将导致数据库查询操作提前结束。

注意:当你在创建带有超时时间或截止时间的一个新context时,总是应该defer对这个context的cancel方法的调用。当包含这个新context的函数退出时,就能释放这个新context所持有的资源。它还将取消queryCtx,当这个新context的cancel方法返回时,就不应该再使用queryCtx

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注