
本文详解 Go 使用 database/sql 驱动操作 MySQL 时,如何正确添加 LIMIT 子句实现分页或结果集截断,并规避常见错误(如 nil 指针、commands out of sync 等)。
本文详解 go 使用 database/sql 驱动操作 mysql 时,如何正确添加 limit 子句实现分页或结果集截断,并规避常见错误(如 `nil` 指针、commands out of sync 等)。
在 Go 中对 MySQL 执行带 LIMIT 的查询,核心原则是:直接将 LIMIT 写入 SQL 字符串中,配合 db.Query()(非 db.Prepare())执行查询。初学者常误用 Prepare() 获取语句对象后未执行,或混淆 Query() 与 QueryRow() 的适用场景,导致返回 <nil></nil> 或触发 commands out of sync 错误。
✅ 正确写法:在 SQL 中内联 LIMIT,使用 Query()
q := "SELECT `data` FROM `page_data` LIMIT 10"
rows, err := db.Query(q)
if err != nil {
log.Fatal("查询失败:", err)
}
defer rows.Close()
for rows.Next() {
var data string
if err := rows.Scan(&data); err != nil {
log.Fatal("扫描失败:", err)
}
fmt.Println(data)
}
// 必须检查 rows.Err() —— 这是迭代结束后验证是否发生错误的关键步骤
if err := rows.Err(); err != nil {
log.Fatal("遍历过程中出错:", err)
}
? 注意:
LIMIT 10等价于LIMIT 0,10(即从第 0 行起取 10 条),如需分页可动态拼接:offset, limit := 20, 10 q := fmt.Sprintf("SELECT `data` FROM `page_data` LIMIT %d, %d", offset, limit)
⚠️ 常见错误与修复
| 错误现象 | 原因 | 修复方式 |
|---|---|---|
Data--- <nil></nil> |
仅调用 db.Prepare() 未执行 Query()/QueryRow(),*sql.Stmt 对象本身不包含数据 |
改用 db.Query() 直接执行;若需复用,再用 stmt.Query()
|
commands out of sync |
在未完全读取前一次 rows 的情况下发起新查询(如忘记 rows.Close() 或未遍历完就 db.Query()) |
务必 defer rows.Close(),且确保 rows.Next() 循环完整执行或显式 break 后仍调用 rows.Close()
|
panic: invalid memory address or nil pointer dereference |
忽略 err 直接操作 rows(当 db.Query() 失败时 rows == nil) |
始终先检查 err != nil,再使用 rows
|
✅ 进阶:安全参数化 LIMIT(避免 SQL 注入)
虽然 LIMIT 子句不支持 ? 占位符(MySQL 驱动明确禁止),但可通过类型校验+白名单方式安全传参:
func queryWithLimit(db *sql.DB, limit int) error {
// 严格校验范围,防止恶意大数
if limit 1000 {
return fmt.Errorf("非法 limit 值: %d,仅允许 1-1000", limit)
}
q := fmt.Sprintf("SELECT id, name FROM users ORDER BY id LIMIT %d", limit)
rows, err := db.Query(q)
if err != nil {
return err
}
defer rows.Close()
// ... 处理 rows
return nil
}
✅ 总结
- ✅
LIMIT是 SQL 语法的一部分,应直接写入查询字符串; - ✅ 读取多行结果用
db.Query()+rows.Next()+rows.Scan(); - ✅ 每次
Query()后必须defer rows.Close()并检查rows.Err(); - ❌ 不要用
db.Prepare()单独获取语句却不执行; - ? 动态 LIMIT 值需手动校验,不可直接拼接用户输入。
遵循以上规范,即可稳定、安全地在 Go 中实现 MySQL 分页与结果集限制。











