Go 的 database/sql 是抽象接口层,需显式导入驱动;sql.Open 不建连,须调用 db.Ping() 验证;密码含特殊字符需 url.QueryEscape;QueryRow 延迟报 sql.ErrNoRows,Query 需手动检查 rows.Err() 并调用 rows.Close();字段名须与列名完全一致且区分大小写;预处理语句需按场景使用;连接池参数 SetMaxOpenConns 等必须合理配置。
Go 的 database/sql 不是数据库驱动,而是抽象接口层 —— 你必须显式导入并注册驱动(如 github.com/lib/pq 或 github.com/go-sql-driver/mysql),否则 sql.Open 会返回 "sql: unknown driver" 错误。
初始化连接时必须调用 db.Ping() 验证连通性
sql.Open 只校验参数、不建立真实连接;真正报错常发生在首次查询时。生产环境务必在初始化后立即执行 db.Ping(),避免服务启动后首请求失败。
- 使用
context.WithTimeout控制探测时间,防止卡死:ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() if err := db.PingContext(ctx); err != nil { log.Fatal("DB ping failed:", err) } - 连接字符串中的密码若含特殊字符(如
@、/),需用url.QueryEscape编码,否则解析失败 - MySQL 驱动默认不启用自动重连,连接中断后需自行处理重试逻辑或使用连接池配置
QueryRow 和 Query 的行为差异直接影响错误处理方式
QueryRow 适用于单行结果(如 SELECT ... LIMIT 1),它把 NoRows 错误延迟到 Scan 阶段才暴露;而 Query 返回 *Rows,需手动检查 rows.Err() 并调用 rows.Close()。
-
QueryRow(...).Scan(&v)失败时,err可能是sql.ErrNoRows,也可能是类型不匹配或网络错误 —— 别直接忽略sql.ErrNoRows - 用
Query循环读取时,必须在for rows.Next()后调用rows.Close(),否则连接不会归还给池,最终耗尽连接数 - 扫描结构体字段时,字段名必须与 SQL 列名(或别名)**完全一致且区分大小写**,否则值为零值且无提示
预处理语句(Prepare)不是性能银弹,要分场景使用
对于高频执行的相同 SQL(尤其带参数的 DML),Stmt 能复用执行计划、减少 SQL 解析开销;但对一次性查询或低频操作,直接用 Exec/Query 更轻量,且避免 Stmt 泄漏风险。