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

使用Go+sqlx从MySQL检索JSON列数据时遇扫描错误求助

Go + sqlx 读取MySQL JSON列扫描报错解决方案

问题背景

MySQL中data列存储的JSON结构如下:

[{"name": "Abc", "ids": [108, 33, 34, 35]}]

使用sqlx执行查询时触发错误:

sql: Scan error on column index 0, name "data": unsupported Scan, storing driver.Value type []uint8 into type *[]test.Data

核心原因

MySQL驱动将JSON列以[]uint8(字节数组)格式返回,sqlx无法自动完成该类型到自定义[]Data切片的映射,需要手动实现类型转换逻辑。


方案1:为自定义切片实现sql.Scanner接口

通过为[]Data创建包装类型并实现sql.Scanner接口,让sqlx能自动完成JSON解析:

步骤1:定义包装类型并实现接口

import (
    "database/sql/driver"
    "encoding/json"
    "fmt"
)

// DataList 包装[]Data类型,用于实现SQL扫描接口
type DataList []Data

// Scan 实现sql.Scanner接口,处理MySQL返回的JSON字节数组
func (d *DataList) Scan(value interface{}) error {
    bytes, ok := value.([]byte)
    if !ok {
        return fmt.Errorf("invalid data type for JSON column: expected []byte, got %T", value)
    }
    return json.Unmarshal(bytes, d)
}

// Value 实现driver.Valuer接口(可选,若需要写入JSON列时使用)
func (d DataList) Value() (driver.Value, error) {
    return json.Marshal(d)
}

步骤2:修改结构体字段类型

将原来的[]Data替换为DataList:

type MainResponse struct {
    Data    DataList `db:"data"`
    Field1  string   `db:"field1"`
    Field2  string   `db:"field2"`
}

type DataStruct struct {
    Data    DataList `db:"data"`
    Field1  string   `db:"field1"`
    Field2  string   `db:"field2"`
}

type Data struct {
    Name store.NullString `db:"name"`
    Ids  []int            `db:"ids"`
}

修改后,原查询代码无需改动,sqlx会自动调用Scan方法完成JSON解析。


方案2:手动扫描后解析JSON

若不想修改结构体类型,可先将JSON列扫描为原始字节类型,再手动解析:

步骤1:修改结构体字段类型

type DataStruct struct {
    Data    json.RawMessage `db:"data"` // 或使用[]byte类型
    Field1  string          `db:"field1"`
    Field2  string          `db:"field2"`
}

步骤2:查询后手动解析JSON

sqlstr := `SELECT field1, field2, data FROM myTable`

records := []DataStruct{}
err := store.DB().Select(&records, sqlstr)
if err != nil {
    return nil, err
}

mainResponses := []MainResponse{}
for _, entry := range records {
    var dataList []Data
    if err := json.Unmarshal(entry.Data, &dataList); err != nil {
        return nil, err
    }
    mainResponses = append(mainResponses, MainResponse{
        Field1: entry.Field1,
        Field2: entry.Field2,
        Data:   dataList,
    })
}

这种方式更灵活,适合临时场景或无需频繁写入JSON列的情况。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 00:50:02