当前位置: 首页 > ai >正文

Golang操作MySQL json字段优雅写法

背景

如下soc_manpower_shift_forecast_tab的version保存一个json格式的结构体。

CREATE TABLE `soc_manpower_shift_forecast_tab` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,`station_id` bigint(20) unsigned NOT NULL DEFAULT '0',`operator` varchar(128) NOT NULL DEFAULT '',`forecast_date` int(10) unsigned NOT NULL DEFAULT '0',`solution_type` tinyint(4) unsigned NOT NULL DEFAULT '0',`version` text NOT NULL,`ctime` int(10) unsigned NOT NULL DEFAULT '0',`mtime` int(10) unsigned NOT NULL DEFAULT '0',PRIMARY KEY (`id`),unique KEY `uniq_station_id_solution_type_date` (`station_id`,`solution_type`, `forecast_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

一般的写法是golang定义的结构体如下,Version是string类型,使用时json反序列化成结构体,写入数据库时把结构体序列化为string。

type SocManpowerShiftForecast struct {ID           int64        `gorm:"column:id;primaryKey" json:"id"`StationID    int64        `gorm:"column:station_id" json:"station_id"`Operator     string       `gorm:"column:operator" json:"operator"`ForecastDate int64        `gorm:"column:forecast_date" json:"forecast_date"` // 使用更友好的时间类型SolutionType int64        `gorm:"column:solution_type" json:"solution_type"`Version      string       `gorm:"column:version" json:"version"` // JSON 文本Ctime        int64        `gorm:"column:ctime" json:"ctime"`Mtime        int64        `gorm:"column:mtime" json:"mtime"`
}

优雅写法

type VersionInfo struct {ShiftList []float64 `json:"shift_list"`
}func (info *VersionInfo) Scan(value interface{}) error {bs, ok := value.([]byte)if !ok {return errors.New("value is not []byte")}return json.Unmarshal(bs, info)
}func (info *VersionInfo) Value() (driver.Value, error) {return json.Marshal(info)
}

Version结构体实现Scan和Value方法

type SocManpowerShiftForecast struct {ID           int64        `gorm:"column:id;primaryKey" json:"id"`StationID    int64        `gorm:"column:station_id" json:"station_id"`Operator     string       `gorm:"column:operator" json:"operator"`ForecastDate int64        `gorm:"column:forecast_date" json:"forecast_date"` // 使用更友好的时间类型SolutionType int64        `gorm:"column:solution_type" json:"solution_type"`Version      *VersionInfo `gorm:"column:version" json:"version"` // JSON 文本Ctime        int64        `gorm:"column:ctime" json:"ctime"`Mtime        int64        `gorm:"column:mtime" json:"mtime"`
}

数据库表结构体直接使用指针结构体即可,完整测试代码如下:

package mysqlimport ("database/sql/driver""encoding/json""errors""example.com/m/test/testutil""example.com/m/util/stringutil""fmt". "github.com/smartystreets/goconvey/convey""testing"
)const SocManpowerShiftForecastTabName = "soc_manpower_shift_forecast_tab"type SocManpowerShiftForecast struct {ID           int64        `gorm:"column:id;primaryKey" json:"id"`StationID    int64        `gorm:"column:station_id" json:"station_id"`Operator     string       `gorm:"column:operator" json:"operator"`ForecastDate int64        `gorm:"column:forecast_date" json:"forecast_date"` // 使用更友好的时间类型SolutionType int64        `gorm:"column:solution_type" json:"solution_type"`Version      *VersionInfo `gorm:"column:version" json:"version"` // JSON 文本Ctime        int64        `gorm:"column:ctime" json:"ctime"`Mtime        int64        `gorm:"column:mtime" json:"mtime"`
}type VersionInfo struct {ShiftList []float64 `json:"shift_list"`
}func (info *VersionInfo) Scan(value interface{}) error {bs, ok := value.([]byte)if !ok {return errors.New("value is not []byte")}return json.Unmarshal(bs, info)
}func (info *VersionInfo) Value() (driver.Value, error) {return json.Marshal(info)
}func Test_ScanValue(t *testing.T) {Convey("ScanValue", t, func() {Convey("ScanValue test1", func() {ctx := testutil.NewContext(testutil.NewContextRequest{})temp := &SocManpowerShiftForecast{ID:           0,StationID:    102,Operator:     "kf",ForecastDate: 1751299200,SolutionType: 1,Version: &VersionInfo{ShiftList: []float64{1.0, 2.0, 3.0, 4.0, 5.0, 6.0},},Ctime: 1751299200,Mtime: 1751299200,}db := testutil.GetDBCommon(ctx)err := db.Table(SocManpowerShiftForecastTabName).Create(temp).ErrorSo(err, ShouldEqual, nil)var res []*SocManpowerShiftForecasterr = db.Table(SocManpowerShiftForecastTabName).Find(&res).ErrorSo(err, ShouldEqual, nil)fmt.Println(stringutil.Object2String(res))})})
}

日志如下:
无论是写入还是读取都没有问题

2025/07/12 22:21:23 /Users/workspace/go-utils/test/mysql/mysql_test.go:60
[5.581ms] [rows:1] INSERT INTO `soc_manpower_shift_forecast_tab` (`station_id`,`operator`,`forecast_date`,`solution_type`,`version`,`ctime`,`mtime`) VALUES (102,'kf',1751299200,1,'{"shift_list":[1,2,3,4,5,6]}',1751299200,1751299200)
.

在这里插入图片描述

http://www.xdnf.cn/news/15206.html

相关文章:

  • 【数据结构初阶】--顺序表(三)
  • 【机器学习实战笔记 16】集成学习:LightGBM算法
  • 【读书笔记】从AI到Transformer:LLM技术演进全解析
  • 智能Agent场景实战指南 Day 11:财务分析Agent系统开发
  • 动态规划基本操作
  • Vue3 学习教程,从入门到精通,Vue3指令知识点及使用方法详细介绍(6)
  • 【TOOL】ubuntu升级cmake版本
  • Linux驱动08 --- 数据库
  • 【PTA数据结构 | C语言版】后缀表达式求值
  • Mamba架构的模型 (内容由deepseek辅助汇总)
  • Edge浏览器:报告不安全的站点的解决方案
  • JAVA线程池详解+学习笔记
  • 鸿蒙NDK开发技巧之-----HAP包如何引入HSP包后,如何给HSP的包传递上下文
  • 非欧几里得空间图卷积算子设计:突破几何限制的图神经网络新范式
  • 从LLM到VLM:视觉语言模型的核心技术与Python实现
  • 如何搭建一个高质量的开放接口平台
  • 顺序队列和链式队列
  • HTML(上)
  • 混合精度训练:梯度缩放动态调整的艺术与科学
  • day4--上传图片、视频
  • AI软件出海SEO教程
  • 从 Spring 源码到项目实战:设计模式落地经验与最佳实践
  • nginx反向代理实现跨域请求
  • 基于springboot+Vue的二手物品交易的设计与实现
  • ABP VNext + OpenTelemetry + Jaeger:分布式追踪与调用链可视化
  • C语言32个关键字
  • WebGL简易教程——结语
  • 可穿戴智能硬件在国家安全领域的应用
  • Openpyxl:Python操作Excel的利器
  • 10. 垃圾回收的算法