
gorm 本身不内置 `decimal` 类型,但可通过第三方库 shopspring/decimal 结合 sql 标签实现高精度小数(如 `decimal(20,8)`)的定义与操作,适用于金融、计费等需精确计算的场景。
在 Go 开发中,尤其是涉及金额、财务结算等对精度要求极高的业务场景,使用 float64 或 float32 存储货币值极易引发浮点误差(如 0.1 + 0.2 != 0.3),因此数据库层面推荐使用 DECIMAL(p,s) 类型(如 DECIMAL(20,8) 表示最多 20 位数字、其中 8 位为小数),而 Go 应用层需匹配支持定点数的类型。
GORM 官方模型定义文档(Define Models)确实未提供原生 decimal 字段类型,但它完全支持通过结构体标签 sql:"type:..." 显式指定数据库列类型,并配合兼容的 Go 类型完成映射。此时,推荐使用社区广泛采用的 shopspring/decimal 库——它提供不可变、高精度的十进制定点数实现,且天然适配 GORM 的扫描与序列化逻辑。
✅ 正确用法示例:
import "github.com/shopspring/decimal"
type Order struct {
ID uint `gorm:"primaryKey"`
Amount decimal.Decimal `gorm:"type:decimal(20,8);not null" json:"amount"`
// 注意:GORM v2 推荐使用 gorm:"..." 标签(非旧版 sql:"..."),兼容性更好
}⚠️ 注意事项:
- 若使用 GORM v2(gorm.io/gorm),请统一使用 gorm:"type:decimal(20,8)" 标签;旧版 GORM v1(github.com/jinzhu/gorm)才使用 sql:"type:decimal(20,8)"。
- decimal.Decimal 类型实现了 driver.Valuer 和 sql.Scanner 接口,可无缝参与 GORM 的读写流程,无需额外配置。
- 在迁移时,确保数据库驱动(如 mysql 或 postgres)支持该类型;例如 MySQL 原生支持 DECIMAL,PostgreSQL 对应 NUMERIC,二者语义一致。
- 避免在业务逻辑中直接用 float64 构造 decimal.Decimal(如 decimal.NewFromFloat(19.99)),因其可能引入浮点误差;推荐使用字符串或整数+精度方式初始化:
amount := decimal.NewFromInt(1999).Div(decimal.NewFromInt(100)) // = 19.99 // 或更安全地: amount := decimal.RequireFromString("19.99")
? 总结:GORM 虽无内置 Decimal 类型,但借助 shopspring/decimal + 精确的 gorm:"type:..." 标签,即可安全、可靠地建模货币字段,兼顾数据库精度与 Go 层语义严谨性。这是生产环境处理金额数据的事实标准方案。










