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

