我在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))
以上就是数据库连接在第一个请求后关闭的详细内容,更多请关注编程网其它相关文章!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
软考中级精品资料免费领
- 历年真题答案解析
- 备考技巧名师总结
- 高频考点精准押题
- 资料下载
- 历年真题
193.9 KB下载数265
191.63 KB下载数245
143.91 KB下载数1142
183.71 KB下载数642
644.84 KB下载数2755