1. 用到的关键技术
-
MySQL
JSON_SET()函数 这是 MySQL 5.7+ 提供的原生 JSON 操作函数,专门用于修改 JSON 字段中的指定路径值,语法:sql
JSON_SET(json字段, '$.路径.子字段', 新值)$:代表 JSON 根节点$.crypto.issuance_volume:定位到options字段下crypto对象里的issuance_volume键- 功能:存在该键则覆盖更新 ,不存在则新增键值对,不会破坏 JSON 字段里的其他数据
-
GORM
Expr()表达式 GORM 的gorm.Expr()用于直接写入原生 SQL 片段,绕过 ORM 的字段映射,实现数据库原生函数调用,这是操作 JSON 字段的常用方案。 -
查询条件设计
go运行
"symbol": data.Symbol, // 币种编码(字符串) "symbol_crc32": php2go.Crc32(data.Symbol) // 币种编码的CRC32哈希值用字符串 + 哈希值复合条件查询,配合数据库索引可以大幅提升查询效率,避免全表扫描。
2. 两段代码的执行效果
假设原 options 字段的 JSON 结构为:
json
{
"crypto": {
"price": 50000,
"issuance_volume": 0,
"market_cap": 0
},
"other_info": "test"
}
执行代码后:
- 第一段:更新
$.crypto.issuance_volume为计算出的流通量 - 第二段:更新
$.crypto.market_cap为接口返回的市值 - 最终 JSON 中仅这两个字段被修改,
price、other_info等数据完全保留
3.补充关键注意事项
-
字段类型要求 数据库中
options字段必须是JSON/JSONB类型,普通字符串类型无法使用JSON_SET函数。 -
空值兼容 如果
issuanceVolume或market_cap为nil/0,JSON_SET会正常写入,不会报错。 -
执行结果校验原代码没有判断更新是否成功,生产环境建议添加错误检查:
go
运行
result := tx.Where(...).Updates(...) if result.Error != nil { // 处理更新失败逻辑,如日志记录、告警 log.Errorf("更新币种%s数据失败:%v", data.Symbol, result.Error) } -
事务建议批量更新币种数据时,建议开启数据库事务,保证批量操作的原子性(要么全部成功,要么全部回滚)。
总结
- 代码核心是通过 MySQL
JSON_SET()+ GORM 原生表达式 ,精准修改optionsJSON 字段的嵌套值,不影响其他字段; - 原代码分两次更新同一条数据存在冗余,合并为一次更新是最优优化方案;
- 该方案是 Go + GORM 操作 MySQL JSON 字段的标准实践,兼顾了灵活性和性能
