go 的 database/sql 仅是接口规范,需配对驱动(如 lib/pq)才能连接数据库;sql.open 不拨号,须调用 db.ping() 校验连接;防 sql 注入须用占位符而非字符串拼接;scan 要求顺序、类型、数量严格匹配 select 列表;务必设置连接池参数(setmaxopenconns 等)。

Go 原生 database/sql 不是数据库驱动,只是接口规范;没配对的驱动(比如 github.com/lib/pq 或 github.com/go-sql-driver/mysql)就根本连不上库。
为什么 sql.Open 不报错却连不上数据库?
sql.Open 只是初始化连接池配置,不真正拨号;真正校验连接要靠 db.Ping()。
- 常见错误现象:
sql.Open返回nilerror,但后续Query报"sql: database is closed"或"dial tcp: lookup..." - 必须显式调用
db.Ping()并检查 error,尤其在服务启动时 - 连接字符串里密码含特殊字符(如
@、/)必须 URL 编码,否则解析失败 - PostgreSQL 示例:
user=me password=%40pass host=localhost port=5432 dbname=test sslmode=disable
怎么安全传参避免 SQL 注入?
永远不用字符串拼接构造 SQL;Query 和 Exec 支持占位符,但各驱动语法不同。
- MySQL 驱动用
?占位:db.Query("SELECT name FROM users WHERE id > ?", minID) - PostgreSQL 驱动用
$1,$2:db.Query("SELECT name FROM users WHERE id > $1", minID) - SQLite 两者都支持,但推荐统一用
?保持可移植性 - 切忌:
fmt.Sprintf("WHERE id = %d", id)—— 这等于裸奔
查询结果怎么正确 Scan 到 struct?
Scan 要求字段顺序、类型、数量严格匹配 SELECT 列表,不是按列名匹配。
- 错误写法:
SELECT id, name FROM users后用Scan(&u.Name, &u.ID)—— 顺序错,值全乱 - 推荐写法:用
SELECT id, name就按&u.ID, &u.Name顺序传参 - 处理 NULL:对应字段必须用指针或
sql.NullString等类型,普通 string 会 panic - 批量查 struct 更稳的方式是用
rows.Scan+ 显式变量,而非直接扫 struct 字段地址(易错序)
最常被忽略的是连接池设置:db.SetMaxOpenConns 和 db.SetMaxIdleConns 不设的话,默认不限制,高并发下可能打爆数据库。还有 db.SetConnMaxLifetime,不设会导致 DNS 变更或连接老化后还复用失效连接。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











