You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Golang DAO函数如何返回MySQL查询错误并避免触发panic

空指针Panic根因

你遇到的空指针panic完全可以对应你注释里描述的“代码执行到err判断处就卡住,后续没有返回内容”的现象,核心触发逻辑是:

  • 当mdao.DB.Query()执行失败时,会返回nil的rows对象以及非空的错误值
  • 原代码的顺序是:拿到rows和err之后,立刻注册defer rows.Close(),完全没有先校验err值
  • 当代码走到if err != nil分支准备返回错误时,函数会优先执行已经注册的defer逻辑,此时会对nil的rows实例调用Close()方法,直接触发空指针panic,中断整个return流程,所以根本没法把错误正常传递给上层调用方
  • panic堆栈里报错的Checkprocessdelete函数存在完全相同的逻辑缺陷,没有等err校验通过就提前使用rows对象、注册关闭逻辑。

另外你写的SQL语句存在语法笔误:SELECT idfrom table where id=?缺少必要空格,本身也会导致Query执行失败。

修复方案
  1. 调整代码执行顺序,先校验Query返回的错误,确认rows非空之后再注册关闭逻辑
  2. 给rows的关闭操作增加兜底空判断,避免极端场景下的空指针问题
  3. 补充rows遍历结束后的错误校验,把遍历过程中出现的底层错误正常返回
  4. 修正SQL语句的语法错误
修复后的DAO代码示例
var sqlQuery = "SELECT id FROM `table` WHERE id = ?"

func (mdao DbConn) Daoprocess(tz *entities.Workflowentity) ([]entities.WorkflowResponseEntity, error) {
	log.Println("In side dao")
	values := []entities.WorkflowResponseEntity{}

	rows, err := mdao.DB.Query(sqlQuery, tz.Id)
	// 先校验Query错误,不碰未确认可用性的rows
	if err != nil {
		log.Printf("Daoprocess Query Error: %v", err)
		return values, err
	}
	// 确认rows非空后再注册关闭逻辑
	defer func() {
		// 兜底判断,避免空指针
		if rows != nil {
			_ = rows.Close()
		}
	}()

	// 逐行读取查询结果
	for rows.Next() {
		value := entities.WorkflowResponseEntity{}
		err := rows.Scan(&value.Id)
		if err != nil {
			log.Printf("Daoprocess Scan Error: %v", err)
			return values, err
		}
		values = append(values, value)
	}

	// 检查遍历过程中可能存在的连接、读取错误
	if err = rows.Err(); err != nil {
		log.Printf("Daoprocess Rows Iterate Error: %v", err)
		return values, err
	}

	return values, nil
}
效果说明
  • 所有数据库层的错误都会通过error返回值正常传递给上层调用方,不会再触发panic中断程序
  • 上层调用方的原有逻辑不需要改动,依然可以通过判断返回的err值完成错误处理流程
  • 兜底的空判断逻辑可以兼容其他DAO函数里同类的空指针隐患,不需要对每个函数都做逐行排查

内容的提问来源于stack exchange,提问作者Subham

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.30 06:27:05