面试题答案
一键面试- 引入context包
在Go语言中,首先需要引入
context
包:
import (
"context"
"database/sql"
"time"
)
- 主函数中的context创建
在微服务的入口函数中,创建一个顶层的
context
,例如:
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// 调用涉及数据库操作的函数
err := performDatabaseOperations(ctx)
if err != nil {
// 处理错误
}
}
这里使用context.WithTimeout
创建了一个带有超时的context
,如果操作在5秒内未完成,context
会被取消。defer cancel()
确保函数结束时,context
相关资源被正确清理。
3. 子操作的context继承
当调用涉及数据库操作的子函数时,将顶层的context
传递下去:
func performDatabaseOperations(ctx context.Context) error {
// 创建数据库连接
db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/database")
if err != nil {
return err
}
defer db.Close()
// 执行第一个数据库操作
err = insertData(ctx, db)
if err != nil {
return err
}
// 执行第二个数据库操作
err = updateData(ctx, db)
if err != nil {
return err
}
return nil
}
insertData
和updateData
函数接受ctx
作为参数,从而继承了顶层context
的取消和超时属性。
4. 子函数中的数据库操作与context处理
例如insertData
函数:
func insertData(ctx context.Context, db *sql.DB) error {
query := "INSERT INTO table_name (column1, column2) VALUES (?,?)"
stmt, err := db.PrepareContext(ctx, query)
if err != nil {
return err
}
defer stmt.Close()
_, err = stmt.ExecContext(ctx, "value1", "value2")
if err != nil {
return err
}
return nil
}
使用PrepareContext
和ExecContext
方法,它们会根据传入的context
进行操作。如果context
被取消(例如用户手动取消或超时),这些操作会被中断。
5. 资源释放顺序
- 首先关闭数据库语句(
stmt.Close()
),确保数据库资源不再被占用。 - 然后关闭数据库连接(
db.Close()
),释放数据库连接资源。 - 对于
context
相关的资源,通过defer cancel()
在函数结束时清理。
通过这种方式,在复杂场景下,context
能够有效管理数据库连接资源,确保在操作取消或超时时,资源能够被正确释放,避免资源泄漏。