Fiber需搭配ORM或原生驱动使用,禁止在Handler中每次新建数据库连接;应全局初始化带连接池的sql.DB或gorm.DB,并在退出前Close();GORM推荐v2,需用errors.Is(err, gorm.ErrRecordNotFound)判空;关闭GORM日志、避免滥用Session和Preload、绑定输入须经校验结构体。

Fiber 本身不提供数据库能力,必须搭配 ORM 或原生驱动使用;直接在路由里写 db.Query 是常见但危险的做法。
为什么不能直接在 Handler 里初始化数据库连接
每次请求都新建连接会快速耗尽数据库连接池,导致 too many connections 错误。Fiber 的 fiber.Ctx 生命周期短,但数据库连接需复用、管理生命周期。
- 连接应作为全局变量或依赖注入对象,在
main()初始化一次 - 推荐用连接池(如
sql.DB或 GORM 的*gorm.DB),它自动复用底层连接 - 若用
pgxpool(PostgreSQL)或mysql.Pool,记得调用Close()在程序退出前释放资源
用 GORM + Fiber 实现安全的用户查询
GORM 是目前与 Fiber 配合最成熟的 ORM,支持自动迁移、预加载、事务等。注意 v2 和 v3 的导入路径不同,当前稳定版仍是 v2。
- 初始化时传入
*gorm.DB到路由闭包或中间件,避免全局变量污染 - 用
c.Params("id")提取路径参数,再用First()查单条,别用Find()无条件查全表 - 务必检查
record.NotFound()而非只看err != nil,否则ErrRecordNotFound会被误判为系统错误
app.Get("/users/:id", func(c *fiber.Ctx) error {
id := c.Params("id")
var user User
if err := db.Where("id = ?", id).First(&user).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return c.Status(404).JSON(fiber.Map{"error": "user not found"})
}
return c.Status(500).JSON(fiber.Map{"error": "database error"})
}
return c.JSON(user)
})
性能关键:别让数据库拖慢 Fiber 的零分配优势
Fiber 的高性能建立在 fasthttp 和零内存分配上,但 GORM 默认日志和反射会悄悄分配内存。高并发下这会抵消框架优势。
- 关闭 GORM 日志:
Config{Logger: logger.Default.LogMode(logger.Silent)} - 避免在 Handler 中频繁调用
db.Session()创建新会话,除非真需要隔离上下文 - 对简单查询,考虑绕过 ORM 直接用
db.Raw().Scan()或sql.DB.QueryRow(),减少结构体映射开销 - 注意
db.Preload()可能引发 N+1,复杂关联建议手写 JOIN 查询
Fiber v3 的 Binder 和数据库结合要注意什么
v3 的 c.Bind() 能自动解析 JSON/Query/Form,但绑定后直接塞进 db.Create() 很危险——缺少字段校验、类型转换可能失败、还容易被恶意字段注入。
- 永远用专用结构体接收输入,加
validate标签(如type CreateUser struct { Name string `validate:"required,min=2"` }) - 绑定后手动映射到领域模型,不要把绑定结构体直接传给
db.Create() - 查询参数(
c.Queries())和路径参数(c.Params())不走 Binder,需单独处理并校验
真正难的不是“怎么查”,而是“查之前有没有做连接复用、查之后有没有正确判断空记录、查的过程中有没有让 ORM 悄悄吃掉 Fiber 的性能红利”。这些点漏一个,QPS 就可能从 12k 掉到 8k。


















