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

GORM向PostgreSQL NUMERIC列插入*big.Int数据报错如何解决

GORM插入*big.Int到PostgreSQL NUMERIC字段解决方案

报错原因

GORM原生未实现*big.Int类型与PostgreSQL NUMERIC类型的映射逻辑,因此要求对应字段要么配置关联外键,要么实现Valuer/Scanner接口。
你之前对Valuer/Scanner接口的理解存在偏差:接口要求返回的driver.Value支持字符串类型,而PostgreSQL驱动会自动将传入的十进制数字符串解析为原生NUMERIC类型存储,不会以文本格式落盘,完全符合你的存储要求。

实现步骤

1. 自定义包装类型并实现接口

import (
    "math/big"
    "database/sql/driver"
    "fmt"
)

// BigInt 包装big.Int适配GORM和PostgreSQL NUMERIC类型
type BigInt big.Int

// Value 实现driver.Valuer接口,转换为十进制字符串供PG驱动解析为NUMERIC
func (b *BigInt) Value() (driver.Value, error) {
    if (*big.Int)(b) == nil {
        return nil, nil
    }
    return (*big.Int)(b).String(), nil
}

// Scan 实现sql.Scanner接口,将PG返回的NUMERIC字符串解析为BigInt
func (b *BigInt) Scan(value interface{}) error {
    if value == nil {
        *b = BigInt{}
        return nil
    }
    str, ok := value.(string)
    if !ok {
        return fmt.Errorf("scan BigInt failed: expected string, got %T", value)
    }
    bi, ok := new(big.Int).SetString(str, 10)
    if !ok {
        return fmt.Errorf("parse BigInt failed: invalid value %s", str)
    }
    *b = BigInt(*bi)
    return nil
}

2. 修改原有结构体字段类型

type T struct {
    PoolAddress_     string `json:"pool_address" gorm:"column:pool_address"`
    BlockNumber_     uint64 `json:"blockNumber" gorm:"column:block_number"`
    TxHash_          string `json:"txnHashC" gorm:"column:transaction_hash"` 
    TransactionHash_ string `json:"transactionHash"`                        
    OldPrice_      *BigInt `json:"old_price" gorm:"column:old_price;type:numeric"`
    NewPrice_      *BigInt `json:"new_price" gorm:"column:new_price;type:numeric"`
    KeeperAddress_ string   `json:"keeper_address" gorm:"column:keeper_address"`
    Source_        string   `json:"source" gorm:"column:source"`
    GasPrice_  uint64 `json:"gasPrice" gorm:"column:gas_price"`
    GasTipCap_ uint64 `json:"GasTipCap" gorm:"column:gas_tip_cap"`
    GasFeeCap_ uint64 `json:"GasFeeCap" gorm:"column:gas_fee_cap"`
    GasUsed_   uint64 `json:"gasUsed" gorm:"column:gas_used"`
    BlockTimestamp_ uint64 `json:"blockTimestamp" gorm:"column:block_timestamp"`
}

3. 业务代码适配

原有*big.Int类型直接强制转换为*BigInt即可正常执行CRUD操作:

// 示例赋值
oldPrice := big.NewInt(4600886000000000000)
newPrice := big.NewInt(4586802000000000000)
record := T{
    OldPrice_: (*BigInt)(oldPrice),
    NewPrice_: (*BigInt)(newPrice),
    // 其他字段赋值逻辑不变
}
// 正常执行GORM插入
if err := db.Create(&record).Error; err != nil {
    // 错误处理
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 10:18:03