目录

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/