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

Go-pg框架中json.RawMessage字段Scan后值为nil的问题排查

解决go-pg中json.RawMessage字段Scan后为nil的问题

问题场景

使用Go语言的PostgreSQL ORM框架go-pg(底层基于pq),定义包含json.RawMessage类型字段的Item结构体,从PostgreSQL加载数据时,该字段经Scan后始终输出nil。尝试两种方案均未解决:

  • 将json.RawMessage别名并实现Scan/Value方法,问题依旧;
  • 封装包含*json.RawMessage字段的JSON结构体,Scan方法内赋值后j.raw的值在外部丢失,Marshal后data字段仍为nil。

错误原因分析

  1. 第一种别名方案逻辑本身正确,但可能存在go-pg结构体标签配置错误;
  2. 第二种封装方案的核心问题是Scan方法使用值接收者:调用Scan时会传入结构体副本,方法内对j.raw的修改仅作用于副本,原结构体字段不会被更新,导致外部无法获取赋值后的值。

简洁解决办法

直接使用json.RawMessage的别名类型,配合指针接收者实现Scan/Value方法,并正确配置go-pg的结构体标签:

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

// JSON 别名json.RawMessage,实现sql.Scanner和driver.Valuer接口
type JSON json.RawMessage

// Scan 指针接收者,确保修改原结构体字段
func (f *JSON) Scan(value interface{}) error {
    if value == nil {
        *f = nil
        return nil
    }
    switch v := value.(type) {
    case []byte:
        *f = append((*f)[0:0], v...) // 复制数据,避免引用临时底层数组
    case string:
        *f = append((*f)[0:0], v...)
    default:
        return fmt.Errorf("无法将类型%T扫描到JSON字段", value)
    }
    return nil
}

// Value 值接收者,返回JSON字符串
func (f JSON) Value() (driver.Value, error) {
    if len(f) == 0 {
        return nil, nil
    }
    return string(f), nil
}

// 定义Item结构体,sql标签指定jsonb对应PostgreSQL的jsonb类型
type Item struct {
    ID   string `sql:"id,pk"`
    Data JSON   `sql:"data,jsonb" json:"data"`
}

使用示例

func main() {
    item := &Item{}
    err := db.Model(item).Where("id = ?", "test").Select()
    if err != nil {
        panic(err)
    }

    fmt.Println(item.Data) // 正常输出JSON数据
    bytes, err := json.Marshal(item)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(bytes)) // data字段正常序列化
}

关键说明

  • 必须使用指针接收者实现Scan方法,才能直接修改原结构体的字段值,避免副本导致的赋值丢失;
  • go-pg结构体标签中的jsonb指定字段对应PostgreSQL的jsonb类型,确保ORM正确处理JSON数据;
  • Scan方法中用append((*f)[0:0], v...)复制数据,避免引用数据库返回的临时底层数组,防止后续数据被覆盖。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 10:44:56