使用defer关闭sql.Rows是否有风险?我的优化方案是否合理?
你的修改方案存在不足,推荐补充nil校验逻辑
你遇到的defer rows.Close()触发panic的核心原因,大概率是传入getResultString的rows参数为nil——当db.Query执行失败返回错误时,rows通常会是nil,直接调用nil指针的Close()方法必然触发panic。
你的当前修改仅对rows.Close()的错误做了捕获打印,但没有处理rows本身为nil的情况,如果调用方传入nil,依然会触发panic,所以这不是完整的推荐做法。
推荐的正确实现方式
需要在defer的匿名函数中先判断rows是否为nil,再执行关闭操作,同时建议使用日志库替代fmt.Println来记录错误(便于线上排查):
import "log" func getResultString(rows *sql.Rows) (*string, error) { defer func() { if rows != nil { // 先判断rows非nil再执行关闭 if err := rows.Close(); err != nil { log.Printf("Failed to close rows: %v", err) } } }() var result string if rows.Next() { if err := rows.Scan(&result); err != nil { return nil, fmt.Errorf("scan err: %v", err) } return &result, nil } return nil, fmt.Errorf("query err: %v", rows.Err()) }
额外优化建议
- 参数前置校验:可以在函数开头就校验
rows是否为nil,提前返回错误,避免后续无效逻辑执行:
func getResultString(rows *sql.Rows) (*string, error) { if rows == nil { return nil, fmt.Errorf("invalid nil rows parameter") } // 后续defer和业务逻辑... }
- 错误处理标准化:统一使用
log或项目内的日志组件记录Close错误,不要用fmt.Println(线上环境无法留存日志,不利于问题排查)。
内容的提问来源于stack exchange,提问作者sclee1
相关产品推荐
相关产品推荐

