sqlx.DB 必须初始化后再传给 Gin 中间件或 Handler,否则调用 db.Query 会 panic;初始化需三步:建立连接、设置连接池参数、设 ConnMaxLifetime;推荐注入到 Gin engine 或自定义 Context,避免 c.Get("db") 魔术字符串。

sqlx.DB 必须初始化后再传给 Gin 中间件或 Handler
没初始化 sqlx.DB 就直接用,Gin 路由里一调 db.Query 就 panic:nil pointer dereference。这不是 Gin 的问题,是 sqlx 连接池没建好。
常见错误写法:var db *sqlx.DB 全局声明后没调 sqlx.Connect 或 sqlx.Open,就塞进 Gin 的 c.Set("db", db) 里。
- 初始化必须包含三步:调
sqlx.Connect(或sqlx.Open+db.Ping())建立连接;调db.SetMaxOpenConns/db.SetMaxIdleConns控制池大小;最好再设db.SetConnMaxLifetime - 别在 Handler 里临时初始化——每个请求都连一次 DB,连接数爆炸
- 推荐把
*sqlx.DB注入到 Gin 的engine或自定义 Context 结构体里,而不是靠c.Get("db")魔术字符串取
查单行用 db.Get,查多行用 db.Select,别混用
用 db.QueryRow().Scan() 或 db.Query().Scan() 是绕过 sqlx 自动映射的“退化用法”,字段名对不上、NULL 值处理错、嵌套结构体扫不到——全得自己扛。
典型报错:sql: Scan error on column index 0: unsupported driver -> Scan pair: *string -> *interface{},就是没走 StructScan 导致的。
-
db.Get(&user, "SELECT * FROM users WHERE id = ?", 123):只接受单行,返回sql.ErrNoRows要用errors.Is(err, sql.ErrNoRows)判断 -
db.Select(&users, "SELECT * FROM users WHERE status = ?", "active"):自动按结构体dbtag 绑定,字段名不一致时静默忽略(不是报错!) - 结构体字段必须带
db:"column_name"标签,尤其 PostgreSQL 下划线命名和 Go 驼峰不匹配时
IN 查询必须拆包 + 重绑定,不能直接传 slice
写 WHERE id IN (?) 然后把 []int64{1,2,3} 当参数传进去,MySQL 报 unsupported type []int64,PostgreSQL 报 pq: syntax error at or near ""——因为原生驱动根本不支持 slice 参数化。
sqlx 提供了标准解法,漏掉任意一步都会失败。
- 先调
sqlx.In("SELECT * FROM orders WHERE user_id IN (?)", ids),得到带占位符的 SQL 和新参数切片 - 再用
db.Rebind(query)把?转成目标驱动格式(MySQL 保持?,PostgreSQL 变成$1, $2, $3) - 最后用
db.Select(&orders, query, args...)——注意args...展开,不是args - 如果
ids是空 slice,sqlx.In返回IN (?)加空参数,执行会报错,得提前判断:if len(ids) == 0 { return nil, nil }
事务中必须用 sqlx.Tx,不能复用 sqlx.DB
在 Gin 的某个 POST 接口里开启事务,但用 db.Query 而不是 tx.Query,结果部分语句走事务、部分走全局连接池——数据不一致且难以复现。
更隐蔽的是:PostgreSQL 的 INSERT ... RETURNING 在事务里用 db.Get 会成功,但返回值来自非事务上下文,回滚后还留着脏数据。
- 事务块必须从
tx, err := db.Beginx()开始,所有操作用tx.Get/tx.Select/tx.Exec - 别用
defer tx.Rollback(),要显式if err != nil { tx.Rollback() },否则成功也 rollback - 事务内想用命名参数(如
:name),得确认驱动支持:PostgreSQL 原生支持,MySQL 和 SQLite 不支持,得用?占位
最常被跳过的点:事务里用了 db 而不是 tx,表面跑通,压测时才暴露数据错乱。别省那几行代码。


















