Golang中请求上下文如何取消查询上下文

Golang中请求上下文如何取消查询上下文 你好,

我目前正在使用请求上下文作为数据库查询上下文的“父”上下文。然而,这会导致日志中出现 context canceled 错误。如果我仅使用 Background 上下文作为“父”上下文,则一切正常。这是预期的行为吗?还是我遗漏了什么?

谢谢

当前情况(有问题)

// ctx 是来自处理程序的 `*http.Request.Context`。
func Insert(ctx context.Context) error {
	ctx, cancel := context.WithTimeout(ctx, 3 * time.Millisecond)
	defer cancel()

	qry := `INSERT INTO users (name) VALUES (?)`

	res, err := r.database.ExecContext(ctx, qry, "hello")
	// ....
}

正常情况

func Insert() error {
	ctx, cancel := context.WithTimeout(context.Background(), 3 * time.Millisecond)
	defer cancel()

	qry := `INSERT INTO users (name) VALUES (?)`

	res, err := r.database.ExecContext(ctx, qry, "hello")
	// ....
}

更多关于Golang中请求上下文如何取消查询上下文的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

这是预期的行为。当父上下文被取消时,所有子上下文也必须被取消。你应该调试父上下文,找出它被取消的原因,可能的取消原因可能是超时或网络断开连接。

更多关于Golang中请求上下文如何取消查询上下文的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这是预期的行为。当使用请求上下文作为父上下文时,如果HTTP请求在处理完成前被取消(比如客户端断开连接),数据库查询也会被取消,导致context canceled错误。

示例代码:

// 正确做法:使用请求上下文但处理取消
func Insert(ctx context.Context) error {
    // 创建超时上下文,继承请求上下文
    queryCtx, cancel := context.WithTimeout(ctx, 3*time.Millisecond)
    defer cancel()
    
    qry := `INSERT INTO users (name) VALUES (?)`
    
    // 执行查询
    res, err := r.database.ExecContext(queryCtx, qry, "hello")
    
    // 检查是否是上下文取消错误
    if err != nil && errors.Is(err, context.Canceled) {
        // 请求被取消,这是正常情况
        return fmt.Errorf("query canceled due to request cancellation")
    }
    
    if err != nil {
        return fmt.Errorf("database error: %w", err)
    }
    
    // 处理结果
    _, err = res.RowsAffected()
    if err != nil {
        return fmt.Errorf("rows affected error: %w", err)
    }
    
    return nil
}

// 如果需要独立于请求的查询,创建分离的上下文
func InsertIndependent() error {
    ctx, cancel := context.WithTimeout(context.Background(), 3*time.Millisecond)
    defer cancel()
    
    qry := `INSERT INTO users (name) VALUES (?)`
    
    res, err := r.database.ExecContext(ctx, qry, "hello")
    if err != nil {
        return fmt.Errorf("database error: %w", err)
    }
    
    _, err = res.RowsAffected()
    if err != nil {
        return fmt.Errorf("rows affected error: %w", err)
    }
    
    return nil
}

使用请求上下文时,查询会随请求取消而终止。使用context.Background()则创建独立上下文,不受请求生命周期影响。两种方式都是有效的,取决于业务需求。

回到顶部