database/sql查询关键在参数传递、结果扫描和错误判断:查单行需用queryrow.scan传字段地址,查多行须用rows.next()循环配合scan并检查rows.err(),且所有rows必须显式close。

database/sql 查询不是“写完 SQL 就能跑”,关键在三件事:参数怎么传、结果怎么扫、错误怎么判。直接用 QueryRow 或 Query 没问题,但错一个指针或漏一次 rows.Next() 就 panic 或静默丢数据。
查单行必须用 Scan 接地址,不能传值
常见错误现象:sql: Scan error on column index 0: unsupported driver -> Scan pair: string -> *int —— 本质是传了值(如 user.ID)而非地址(&user.ID)。
-
QueryRow返回的是单行结果句柄,Scan必须接收每个字段的指针,顺序严格对应 SELECT 列序 - 结构体字段名要和列名匹配(默认全小写),或加
db:"id"tag 显式映射 - 查不到时返回
sql.ErrNoRows,不是nil;其他错误(如类型不匹配)需单独处理 - 示例:
var user struct{ ID int; Name string } err := db.QueryRow("SELECT id, name FROM users WHERE id = ?", 123).Scan(&user.ID, &user.Name)
查多行必须配合 rows.Next() 循环,不能只调一次 Scan
常见错误现象:只循环一次就退出、Scan 调两次、漏掉 rows.Err() 检查 —— 导致最后一行没读、错误被吞、或 panic。
-
rows.Next()是游标推进动作,每次调用才准备下一行数据;Scan只读当前行 - 必须在
for rows.Next()内完成Scan,且每次都要检查Scan错误 - 循环结束后必须调
rows.Err(),判断是否因 I/O 或类型错误提前中断 - 示例:
rows, _ := db.Query("SELECT id, name FROM users") defer rows.Close() for rows.Next() { var id int var name string if err := rows.Scan(&id, &name); err != nil { log.Fatal(err) // 不要忽略 } fmt.Printf("%d: %s\n", id, name) } if err := rows.Err(); err != nil { log.Fatal(err) }
MySQL/PostgreSQL/SQL Server 占位符不通用,别混用
常见错误现象:ERROR 1064: You have an error in your SQL syntax —— 实际是驱动不认 $1 或 :name,只认自己的占位符。
- MySQL 驱动(
go-sql-driver/mysql)只支持?,不支持命名参数 - PostgreSQL 驱动(
lib/pq)支持$1、$2,也支持:name(但需NamedQuery配合) - SQL Server 驱动(
go-mssqldb)用@p1,不是?或$1 - 想跨数据库写 SQL?要么统一用
?+sqlx.Rebind(),要么按驱动切分支
sqlx 的 Get 和 Select 不是语法糖,是结构体扫描开关
常见错误现象:sql: Scan error on column index 0: unsupported driver -> Scan pair: *string -> *interface{} —— 直接调 db.QueryRow(...).Scan(&user) 会失败,因为标准库不知道结构体字段对应哪列。
-
sqlx.Get内部调QueryRow+StructScan,自动按字段名或dbtag 匹配列;QueryRow不做这步 - 必须传结构体地址:
err := db.Get(&user, "SELECT ..."),传值或传指针的指针都会 panic - 字段 tag 示例:
ID int `db:"id"`,否则按Id→id小写匹配(MySQL 默认不区分大小写,但列名含下划线时易错) - 没查到数据时仍返回
sql.ErrNoRows,行为和原生一致
rows 对象都必须显式 Close(),哪怕用了 defer;QueryRow 看似单行,底层仍占用连接,不 Close 可能快速耗尽连接池。另外,Scan 时如果某列为 NULL,对应字段必须是 sql.NullInt64 这类可空类型,普通 int 会直接报错。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











