问题内容
我在golang上写api,遇到了错误。在一个请求服务器返回错误后,sql 数据库已关闭。我想通过上下文传输数据库连接。
main.go
func main() { app := fiber.new() db, err := sqlx.connect("pgx", os.getenv("postgresql_url")) if err != nil { panic(err) } if err = db.ping(); err != nil { panic(err) } db.setmaxopenconns(10) db.setmaxidleconns(5) db.setconnmaxlifetime(5 * time.minute) db.setconnmaxidletime(5 * time.minute) defer db.close() configure_router.configurerouter(app, db) if err = app.listen(os.getenv("port")); err != nil { log.fatalln(err) }}
登录后复制
configure_router.go
func configurerouter(app *fiber.app, db *sqlx.db) { //middlewares app.use(logger.new(logger.config{ format: "[${ip}]:${port} ${time} ${status} - ${method} ${path}", })) app.use(cors.new(cors.config{ //alloworigins: "http://localhost:3000", allowheaders: "origin, content-type, accept", })) app.use("/api", func(ctx *fiber.ctx) error { ctx.context().setuservalue("dbconn", db) return ctx.next() }) //authentication endpoints app.post("api/register", register.register) app.post("api/auth/login", login.login)}
登录后复制
注册.go
func register(ctx *fiber.ctx) error { conn := ctx.context().uservalue("dbconn").(*sqlx.db) var in in if err := ctx.bodyparser(&in); err != nil { return make_response.makeinforesponse(ctx, fiber.statusunprocessableentity, 1, err.error()) } if in.email == "" || in.password == "" { return make_response.makeinforesponse(ctx, fiber.statusbadrequest, 1, "incorrect data input") } elementexist := false err := conn.get(&elementexist, "select exists(select email from users where email = $1)", in.email) // here programm fall in second request if err != nil { return make_response.makeinforesponse(ctx,fiber.statusinternalservererror, 1, err.error()) } if elementexist { return make_response.makeinforesponse(ctx, fiber.statusbadrequest, 1, "user already registered!") } passwordhash, err := hash_passwords.hashpassword(in.password) if err != nil { return err } _, err = conn.exec("insert into users (email, password_hash) values ($1, $2)", in.email, passwordhash) if err != nil { return make_response.makeinforesponse(ctx, fiber.statusinternalservererror, 1, err.error()) } return make_response.makeinforesponse(ctx, fiber.statusok, 0, "registration was successful!")}
登录后复制
如果我在 /api/register 中发送请求并且用户已经在第一个请求中注册,我会得到
要求:
{ "email": "[email protected]", "password": "123123123"}
登录后复制
第一反应:
{ "error_code": 0, "message": "user already registered!"}
登录后复制
但是如果我想发送另一个请求,我会得到:
{ "error_code": 1, "message": "sql: database is closed",}
登录后复制
正确答案
我想通过上下文传输数据库连接。
不要。这不仅是不好的做法,而且实际上是 fasthttp.requestctx 本身在每次请求后关闭数据库。上下文应仅包含请求特定值。全局数据库连接几乎不是特定于请求的。
请参阅 setuservalue 的文档,特别是最后一个段落:
从顶层requesthandler返回后,所有值都会从ctx中删除。此外,在从 ctx 中删除值之前,会在每个实现 io.closer 的值上调用 close 方法。
一个快速修复方法是在闭包中捕获数据库:
func Register(db *sqlx.DB) (fn func(*fiber.Ctx) error) { return func(ctx *fiber.Ctx) error { // ... elementExist := false err := db.Get(&elementExist, "select exists(select email from users where email = $1)", in.Email) // ... }}// ...// delete this or comment it out// app.Use("/api", func(ctx *fiber.Ctx) error {// ctx.Context().SetUserValue("dbConn", db)// return ctx.Next()// })app.Post("api/register", register.Register(db))
登录后复制
以上就是数据库连接在第一个请求后关闭的详细内容,更多请关注【创想鸟】其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。
发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2485365.html