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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 21:27:04