
本文详解如何在 Go 中使用 database/sql 包安全、正确地执行带 LIMIT 子句的 MySQL 查询,并规避常见错误(如 nil 指针解引用、commands out of sync),附可运行示例与关键注意事项。
本文详解如何在 go 中使用 database/sql 包安全、正确地执行带 limit 子句的 mysql 查询,并规避常见错误(如 nil 指针解引用、commands out of sync),附可运行示例与关键注意事项。
在 Go 中操作 MySQL 时,设置查询结果限制(即 SQL 的 LIMIT)与 PHP 等语言逻辑一致——直接将 LIMIT 写入 SQL 字符串即可,无需特殊 API。但初学者常因混淆 Prepare/Query/QueryRow 的用途,或忽略错误处理与资源释放,导致程序 panic 或返回 <nil></nil>。
✅ 正确做法:使用 db.Query() 执行带 LIMIT 的查询
LIMIT 是标准 SQL 子句,Go 的 MySQL 驱动(如 go-sql-driver/mysql)完全支持。只需将其写入查询语句字符串中:
q := "SELECT `data` FROM `page_data` LIMIT 10" // 获取前 10 条
// 或带偏移量
q := "SELECT `data` FROM `page_data` LIMIT 20, 5" // 跳过前 20 条,取 5 条
// 或使用参数化防止 SQL 注入(推荐用于动态 limit/offset)
limit := 10
offset := 0
q := "SELECT `data` FROM `page_data` LIMIT ? OFFSET ?"
rows, err := db.Query(q, limit, offset) // 自动绑定参数
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() —— Next() 循环结束后可能仍有潜在错误
if err := rows.Err(); err != nil {
log.Fatal("遍历结果时出错:", err)
}
⚠️ 注意:
LIMIT ?和OFFSET ?在 MySQL 驱动中支持参数占位符(需驱动版本 ≥ 1.6.0),但部分旧版或兼容模式下可能不支持。若报错Error 1064: You have an error in your SQL syntax,请改用字符串拼接(仅限可信输入):limit, offset := 10, 0 q := fmt.Sprintf("SELECT `data` FROM `page_data` LIMIT %d OFFSET %d", limit, offset)
❌ 常见错误分析与修复
-
错误 1:误用
Prepare+ 忽略执行myquery, err := db.Prepare("SELECT pages_old FROM app_library") // ← 仅准备,未执行! fmt.Println("Data---", myquery) // 输出 *sql.Stmt 对象,非数据 → 显示 `<nil>` 是误解</nil>✅ 修正:
Prepare后必须调用.Query()或.QueryRow()才能获取结果:stmt, _ := db.Prepare("SELECT pages_old FROM app_library LIMIT ?") defer stmt.Close() rows, _ := stmt.Query(5) // 传入 LIMIT 参数 错误 2:
commands out of sync
此错误通常因未关闭前一个rows就发起新查询,或在rows.Next()循环中提前return却未rows.Close()。
✅ 强制保障:始终用defer rows.Close(),并在循环后检查rows.Err()。-
错误 3:
nil pointer dereferencepanic
多因err非空时未处理,继续调用rows.Scan()。务必在db.Query()后立即检查err:rows, err := db.Query(q) if err != nil { log.Fatal("Query failed:", err) // 不要忽略! } defer rows.Close()
? 最佳实践总结
- ✅ 优先使用
db.Query()执行带LIMIT的只读查询; - ✅ 动态 limit/offset 场景,优先尝试参数化(
LIMIT ?, ?),失败则转义后拼接; - ✅ 每次
Query()后必须defer rows.Close(),并在for rows.Next()后调用rows.Err(); - ✅ 避免在循环中
return或panic前遗漏rows.Close()——defer是最可靠的保障; - ✅ 生产环境务必配置连接池(
db.SetMaxOpenConns()/db.SetMaxIdleConns()),避免高并发下耗尽连接。
遵循以上规范,即可在 Go 中稳定、高效地实现 MySQL 分页与结果集限制。











