gorm分页查询count报错 sql no rows in result set
gorm分页查询count报错 sql: no rows in result set
背景
最近在做一个Golang项目的列表分页功能时,用GORM的Count方法统计总数突然报了“sql: no rows in result set”错误。
本以为是简单的空数据问题,折腾了小半天才找到根因,索性整理成笔记分享给踩过同款坑的朋友
复现
先贴一下最初的报错代码,这是很多GORM新手都会写的分页逻辑——先查总数再查列表数据:
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// 定义用户模型
type User struct {
gorm.Model
Name string
Age int
Email string
}
func main() {
// 数据库连接(省略配置,实际项目需替换为真实信息)
dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic("数据库连接失败")
}
// 分页参数
page := 1
pageSize := 10
offset := (page - 1) * pageSize
var total int64
var users []User
// 第一步:统计总数——此处报错sql: no rows in result set
err = db.Where("age > ?", 18).Find(&users).Count(&total).Error
if err != nil {
println("统计总数失败:", err.Error())
return
}
// 第二步:查询列表数据
err = db.Where("age > ?", 18).Offset(offset).Limit(pageSize).Find(&users).Error
if err != nil {
println("查询列表失败:", err.Error())
return
}
println("总条数:", total, "当前页数据量:", len(users))
}这段代码看起来没毛病,但当“age>18”的用户数据为空时,Count方法就会抛出“sql: no rows in result set”错误。一开始我以为是GORM的BUG,后来翻了文档才发现是自己的用法出了问题
原因
为什么空数据会导致Count报错?核心原因是GORM的Count方法会复用前面的查询链,且当查询链中存在Find时,空结果会触发错误。
仔细看代码会发现,我把Find和Count写在了同一条查询链里:db.Where(…).Find(&users).Count(&total)。这种写法会让GORM先执行Find查询(获取列表数据),再基于Find的查询条件执行Count统计。
而当Find查询不到数据时,GORM会返回sql.ErrNoRows错误,这个错误会直接传递给后续的Count方法,导致统计步骤也失败。
但实际上,我们想要的是“没有数据时total=0”,而不是报错。
解决
(一)方式一:拆分查询(推荐)
既然同一条查询链会传递错误,那我们就把Count和Find拆分成两条独立的查询链,各自使用Where条件。这样即使列表查询为空,Count统计也能正常返回0
// 优化后:拆分Count和Find的查询链
var total int64
var users []User
// 第一步:单独统计总数(无数据时返回0,不报错)
err = db.Model(&User{}).Where("age > ?", 18).Count(&total).Error
if err != nil {
println("统计总数失败:", err.Error())
return
}
// 第二步:查询列表数据(空数据时err为sql.ErrNoRows,可按需处理)
err = db.Where("age > ?", 18).Offset(offset).Limit(pageSize).Find(&users).Error
if err != nil && err != gorm.ErrRecordNotFound {
println("查询列表失败:", err.Error())
return
}
println("总条数:", total, "当前页数据量:", len(users)) // 空数据时total=0,len(users)=0这里有个小细节:Count前加了Model(&User{}),作用是明确指定统计的表模型,即使后续没有Find也能正确关联表结构,我们非常推荐养成这个习惯。
(二)方式二:错误类型判断
如果不想改动查询链结构,也可以在报错后判断错误类型——当错误是sql.ErrNoRows时,手动将total设为0,其他错误再正常抛出:
import "database/sql"
// 原有查询链保留,增加错误判断
err = db.Where("age > ?", 18).Find(&users).Count(&total).Error
if err != nil {
// 判断是否为“无数据”错误,是则重置total为0
if err == sql.ErrNoRows {
total = 0
} else {
println("统计总数失败:", err.Error())
return
}
}这种方式适合不想大幅修改代码的场景,但要注意导入database/sql包才能判断错误类型,且兼容性不如方案一。
版权声明
未经授权,禁止转载本文章。
如需转载请保留原文链接并注明出处。即视为默认获得授权。
未保留原文链接未注明出处或删除链接将视为侵权,必追究法律责任!
本文原文链接: https://fiveyoboy.com/articles/go-gorm-count-err/
备用原文链接: https://blog.fiveyoboy.com/articles/go-gorm-count-err/