Rumah > pembangunan bahagian belakang > Golang > Sambungan pangkalan data ditutup selepas permintaan pertama

Sambungan pangkalan data ditutup selepas permintaan pertama

PHPz
Lepaskan: 2024-02-06 10:57:08
ke hadapan
1146 orang telah melayarinya

Sambungan pangkalan data ditutup selepas permintaan pertama

问题内容

我在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)
    }
}
Salin selepas log masuk

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)
}
Salin selepas log masuk

注册.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!")
}
Salin selepas log masuk

如果我在 /api/register 中发送请求并且用户已经在第一个请求中注册,我会得到

要求:

{
  "email": "[email protected]",
  "password": "123123123"
}
Salin selepas log masuk

第一反应:

{
   "error_code": 0,
   "message": "user already registered!"
}
Salin selepas log masuk

但是如果我想发送另一个请求,我会得到:

{
   "error_code": 1,
   "message": "sql: database is closed",
}
Salin selepas log masuk


正确答案


我想通过上下文传输数据库连接。

不要。这不仅是不好的做法,而且实际上是 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))
Salin selepas log masuk

Atas ialah kandungan terperinci Sambungan pangkalan data ditutup selepas permintaan pertama. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan