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执行失败。
修复方案
- 调整代码执行顺序,先校验Query返回的错误,确认rows非空之后再注册关闭逻辑
- 给rows的关闭操作增加兜底空判断,避免极端场景下的空指针问题
- 补充rows遍历结束后的错误校验,把遍历过程中出现的底层错误正常返回
- 修正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
相关产品推荐
相关产品推荐

