背景
如下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 mysql
import (
"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).Error
So(err, ShouldEqual, nil)
var res []*SocManpowerShiftForecast
err = db.Table(SocManpowerShiftForecastTabName).Find(&res).Error
So(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)
.