我应该将 context.Context 传递给 Go 中的底层数据库方法吗?

我在这里使用半代码只是为了展示我对代码中发生的事情的意图,而不是让问题复杂化。


我有一个main.go文件调用连接到 mongoDB 数据库的方法:


mStore := store.NewMongoStore()

在NewMongoStore我有client.Connect用于连接数据库的上下文中:


ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)

defer cancel()

现在main.go我以这种方式将商店传递给我的路由器控制器文件:


routes.GenericRoute(router, mStore)

在GenericRoute我得到 mStore 并将其传递给函数处理程序时:


func GenericRoute(router *gin.Engine, mStore store.Store) {

    router.POST("/users", controllers.CreateUser(mStore))

}

现在CreateUser我再次创建一个上下文,如下所示,将文档插入 MongoDB:


ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)

defer cancel()


insertedId, err := repo.CreateUser(ctx, newUser{"John", "Doe"})

在这里,我将上下文传递给以createUser插入一个新文档。


正如您在某些部分看到的,我已经通过了上下文,而在某些部分我没有。我真的不知道我应该做什么?使用上下文的正确方法是什么?我应该始终传递上下文还是完全可以创建这样的新上下文而不在方法参数中传递上下文。


这种编码的最佳实践是什么?从性能的角度来看,哪个更好?


偶然的你
浏览 91回答 2
2回答

www说

根据我的经验,Context有两个主要用例:传递信息。对于您的问题,您可能希望request_id为每个请求生成一个并将其传递到代码的最低部分,并记录它request_id以在整个代码库中进行错误跟踪。此功能并不总是有用,例如您想要初始化 MongoDB 连接,但它是在服务启动期间完成的。此时没有有意义的上下文,context.Background超时应该足够了。对从 中检索到的变异值要小心,Context如果您要传递Context所有内容,这可能会导致并发访问。自动取消和超时。这两个功能并非无中生有,您需要调整代码以处理来自Context. 但是大多数带有参数的第三方库和标准库Context都可以很好地处理这两个特性(例如数据库库、HTTP 调用库)。Context使用此功能,您可以在失效 后自动回收资源。有时您会想要停止这种级联行为,例如在后台 goroutine 中写入日志,那么您需要创建一个新的 goroutinecontext.Background()以避免这些写入在上游上下文被取消后被取消。context.Background()还会清除信息上下文,因此有时您需要从上游上下文中提取上下文信息,并手动将它们附加到这个新上下文中。Context将参数强制用于所有函数有点矫枉过正,(添加Context到简单greatestCommonDivisor函数没有意义)但是将Context参数添加到您需要的任何地方永远不会造成伤害。Context具有足够好的性能,对于您的用例(HTTP 服务器和数据库编写),它不应该对您的服务造成可见的开销。

紫衣仙女

我对自己的问题找到了一个有趣的答案,所以如果有同样的问题,我更愿意把它放在这里供未来的用户使用。如果我将连接到 Mongo 的 SAME 上下文传递给 touserController并将其进一步向下传递以CreateUser运行:ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)注意:不是在函数中取消上下文,而是在NewMongoStore函数defer cancel()中取消上下文main。10 秒后,如果你打电话POST /users,你会得到context deadline exceeded,所以基本上你不能使用这个上下文来做其他事情,你必须在每次CreateUser调用时创建新的上下文。所以我写的很好。在我的示例中,我等待 10 秒连接到mongo,插入操作上下文等待 1 秒。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go