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

Golang中SQL查询结果JSON返回时数值被识别为Base64的问题

解决SQL查询数值类型被JSON编码为Base64的问题

这个问题的根源很明确:当你用rows.MapScan(results)时,sqlx对于numeric/float这类非整数数值类型,并没有自动转换成Go的数值类型(比如float64),而是返回了原始的字节数组([]byte)或者sql.RawBytes。而Go标准库的json编码器在处理[]byte类型时,默认会将其编码为Base64字符串,这就是你看到QTY字段变成"OC4wMA=="的原因(解码后其实是8.00)。

下面给你几个可行的解决方案:

方案1:手动转换Map中的字节类型值

在MapScan之后,遍历结果Map,将[]byte类型的数值转换为对应的数值类型:

rows, err := db.Queryx(query)
if err != nil {
    // 处理查询错误
    return
}
defer rows.Close()

enc := json.NewEncoder(w)
for rows.Next() {
    results := make(map[string]interface{})
    err = rows.MapScan(results)
    if err != nil {
        // 处理扫描错误
        continue
    }

    // 遍历Map,转换[]byte类型的数值
    for key, val := range results {
        if byteVal, ok := val.([]byte); ok {
            // 尝试转换为float64
            floatVal, err := strconv.ParseFloat(string(byteVal), 64)
            if err == nil {
                results[key] = floatVal
                continue
            }
            // 如果是整数形式的字节,也可以尝试转int
            intVal, err := strconv.Atoi(string(byteVal))
            if err == nil {
                results[key] = intVal
            }
        }
    }

    if err := enc.Encode(results); err != nil {
        fmt.Fprintf(w,"%s\n", results)
    }
}

如果你的数值是高精度的decimal类型,推荐使用github.com/shopspring/decimal库来避免精度损失:

import "github.com/shopspring/decimal"

// ... 其他代码 ...
for key, val := range results {
    if byteVal, ok := val.([]byte); ok {
        decVal, err := decimal.NewFromString(string(byteVal))
        if err == nil {
            results[key] = decVal
        }
    }
}

方案2:使用结构体代替Map(推荐)

定义一个与查询结果字段匹配的结构体,明确指定字段类型,然后用rows.StructScan代替MapScan。这种方式更可靠,sqlx会自动帮你完成类型映射:

// 定义结构体,字段名和数据库列名对应(可以用db标签指定)
type OrderResult struct {
    ID  int     `db:"ID"`
    QTY float64 `db:"QTY"`
    // 如果是高精度decimal,用decimal.Decimal类型
    // QTY decimal.Decimal `db:"QTY"`
}

// ... 其他代码 ...
rows, err := db.Queryx(query)
if err != nil {
    // 处理错误
    return
}
defer rows.Close()

enc := json.NewEncoder(w)
for rows.Next() {
    var res OrderResult
    err = rows.StructScan(&res)
    if err != nil {
        // 处理扫描错误
        continue
    }

    if err := enc.Encode(res); err != nil {
        fmt.Fprintf(w,"%s\n", res)
    }
}

这个方案的优势在于类型明确,避免了Map带来的类型不确定性,同时也更符合Go的类型安全原则。

额外提示

  • 如果你使用的是PostgreSQL等数据库,确保驱动已经正确配置,有些驱动需要显式设置类型映射才能正确转换numeric类型。
  • 对于decimal类型,尽量避免直接用float64存储,防止精度丢失,使用专门的decimal库是更好的选择。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:22:11