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
相关产品推荐
相关产品推荐

