Golang中能否不先Scan就直接返回数据库查询的*sql.Rows结果
问题排查与解决方案
核心原因
你的代码问题出在defer语句的执行时机不符合设计预期:
Go语言中defer绑定的是当前所在函数的退出时机,你在model.Query函数内定义的defer connect.Close()和defer rows.Close(),都会在Query函数执行完成、将rows返回给调用方之前就触发执行。
等ProductList拿到返回的rows对象时,数据库连接已经被关闭、结果集资源也已经被释放,自然无法读取到任何数据,也不会抛出显式的运行错误。
另外你调用侧的import存在笔误:import "hb-backend=v1/model" 中的等号需要改为减号,和实际包路径对齐。
可行实现方案
方案1:封装扫描逻辑,完全控制资源生命周期(推荐,符合你最初的设计目标)
该方案将rows的遍历、关闭逻辑全部收拢到公共查询函数内部,无需调用方处理资源释放,从根源上避免漏写defer rows.Close()的问题:
// model层公共查询函数,传入扫描回调处理每行数据 func Query(query string, scanFn func(*sql.Rows) error) error { connect, err := database.Connect() if err != nil { fmt.Println("Connection Failed") return err } defer connect.Close() rows, err := connect.Query(query) if err != nil { return err } defer rows.Close() for rows.Next() { if err := scanFn(rows); err != nil { return err } } // 不要遗漏检查rows遍历过程中产生的错误 return rows.Err() }
调用侧代码:
func ProductList() ([]Hasil, error) { var result []Hasil err := model.Query("SELECT * FROM alamat_store", func(rows *sql.Rows) error { var each Hasil err := rows.Scan(&each.Id_alamat_store, &each.Id_tk, &each.Alamat, &each.Id_wil, &each.Latitude, &each.Longitude) if err != nil { return err } result = append(result, each) return nil }) return result, err }
方案2:返回资源控制权给调用方
如果你坚持要返回rows对象给调用方自主处理,就不能在公共查询函数内关闭连接和结果集,需要同时将数据库连接对象返回给调用方,避免连接被GC回收导致rows失效:
func Query(query string) (*sql.Rows, *sql.DB, error){ connect, err := database.Connect() if err != nil{ fmt.Println("Connection Failed") return nil, nil, err } rows, err := connect.Query(query) if err != nil{ // 出错时提前释放连接 connect.Close() return nil, nil, err } return rows, connect, nil }
调用侧代码:
func ProductList() ([]Hasil, error){ rows, connect, err := model.Query("SELECT * FROM alamat_store") if err != nil { return nil, err } // 调用方自行管理资源释放 defer connect.Close() defer rows.Close() var result []Hasil for rows.Next(){ var each = Hasil{} err := rows.Scan(&each.Id_alamat_store, &each.Id_tk, &each.Alamat, &each.Id_wil, &each.Latitude, &each.Longitude) if err != nil { return nil, err } result = append(result, each) } return result, rows.Err() }
内容的提问来源于stack exchange,提问作者Agung
相关产品推荐
相关产品推荐

