最新公告
  • 欢迎您光临码农资源网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!加入我们
  • 数据库连接在第一个请求后关闭

    数据库连接在第一个请求后关闭

    问题内容

    我在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}n",
        }))
    
        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))
    
    想要了解更多内容,请持续关注码农资源网,一起探索发现编程世界的无限可能!
    本站部分资源来源于网络,仅限用于学习和研究目的,请勿用于其他用途。
    如有侵权请发送邮件至1943759704@qq.com删除

    码农资源网 » 数据库连接在第一个请求后关闭
    • 7会员总数(位)
    • 25846资源总数(个)
    • 0本周发布(个)
    • 0 今日发布(个)
    • 293稳定运行(天)

    提供最优质的资源集合

    立即查看 了解详情