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

Golang中sql.RawBytes在Scan循环中被相互覆盖的问题求助

问题分析与修复方案

问题根源

sql.RawBytes本质是[]byte的别名,数据库驱动为了减少内存分配,会复用同一块底层字节数组来存储每次Scan的结果。你当前的代码仅对rawResult做了浅拷贝(copy(currentResult, rawResult)只是复制了切片的引用,而非底层字节数据),导致results中所有元素都指向驱动复用的同一块内存。当下一次Scan执行时,旧的结果会被新数据覆盖,出现你看到的串值问题。

修复代码

需要对每个sql.RawBytes元素做深拷贝,将底层字节复制到独立的新切片中,避免后续Scan操作篡改已保存的结果:

import (
   "database/sql"
   "log"
   _ "github.com/denisenkom/go-mssqldb"
)

func fetchRawResults(rows *sql.Rows, numColumns int) ([][]sql.RawBytes, error) {
   results := make([][]sql.RawBytes, 0)

   dest := make([]interface{}, numColumns)
   rawResult := make([]sql.RawBytes, numColumns)
   for i := range dest {
      dest[i] = &rawResult[i]
   }

   for rows.Next() {
      err := rows.Scan(dest...)
      if err != nil {
         return nil, err // 替换log.Fatal,让上层处理错误
      }

      // 深拷贝每个字段的底层字节
      currentResult := make([]sql.RawBytes, numColumns)
      for idx, val := range rawResult {
         if val != nil {
            currentResult[idx] = make(sql.RawBytes, len(val))
            copy(currentResult[idx], val)
         }
      }

      results = append(results, currentResult)
   }

   // 必须检查rows遍历后的错误(Next返回false可能是因为出错)
   if err := rows.Err(); err != nil {
      return nil, err
   }

   rows.Close()
   return results, nil
}

额外注意事项

  • 移除了log.Fatal(err):直接终止程序过于粗暴,改为返回错误让调用方处理更合理。
  • 新增rows.Err()检查:rows.Next()返回false时,可能是遍历完成,也可能是发生了错误,必须显式检查这个错误才能保证数据完整性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 06:55:24