mysql在5.6版本时,不支持直接Json存储,我们一般存储成varchar等string类型。编码时,我们也是将数据json格式化后,存储。

从5.7版开始,开始支持JSON格式存储,那么在使用Go存储对应的字段时,如何定义struct,就是一个问题。现有orm一般没有支持json类型的定义。如果struct定义为string类型,会导致一些问题。例如JSON数据为空时,存储的是””, 有时候会导致一些差别。

例如使用gorm存储数据时,不支持Json类型的数据结构。
为解决这个问题,我们可以自定义一个JSON的struct

Mysql结构

如在Mysql中定义了如下的表结构

1
2
3
4
5
6
7
8
9
10
CREATE TABLE `report` (
`id` bigint(20) NOT NULL,
`query_param` json DEFAULT NULL,
`create_by` varchar(50) DEFAULT NULL COMMENT '创建人',
`create_date` timestamp NULL DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(50) DEFAULT NULL COMMENT '修改人',
`update_date` timestamp NULL DEFAULT NULL COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

过去我们会定义query_paramvarchar等字符串类型,在mysql 5.7中我们可以直接定义为json类型

自定义JSON类型

这样我们在orm中定义struct时,就会遇到问题。
过去我们会将Json字段定义为string

1
2
3
4
5
6
7
8
9
type Report struct {
ID int64 `json:"id"`
QueryParam string `json:"queryParam"`
CreateBy string `json:"createBy"`
CreateDate time.Time `json:"createDate"`
UpdateBy string `json:"updateBy"`
UpdateDate time.Time `json:"updateDate"`
}

但这样在存储数据时,是有些差别的。如果queryParam为空时,此时存储为””,非NULL。与我们的设计是不同的。

为解决这个问题,可以自定义一个JSON类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package models

import (
"bytes"
"database/sql/driver"
"errors"
)

type JSON []byte

func (j JSON) Value() (driver.Value, error) {
if j.IsNull() {
return nil, nil
}
return string(j), nil
}

func (j *JSON) Scan(value interface{}) error {
if value == nil {
*j = nil
return nil
}
s, ok := value.([]byte)
if !ok {
errors.New("Invalid Scan Source")
}
*j = append((*j)[0:0], s...)
return nil
}

func (m JSON) MarshalJSON() ([]byte, error) {
if m == nil {
return []byte("null"), nil
}
return m, nil
}

func (m *JSON) UnmarshalJSON(data []byte) error {
if m == nil {
return errors.New("null point exception")
}
*m = append((*m)[0:0], data...)
return nil
}

func (j JSON) IsNull() bool {
return len(j) == 0 || string(j) == "null"
}

func (j JSON) Equals(j1 JSON) bool {
return bytes.Equal([]byte(j), []byte(j1))
}

这样我们在定义models时,可以指定为JSON类型

1
2
3
4
5
6
7
8
9
type Report struct {
ID int64 `json:"id"`
QueryParam JSON `json:"queryParam"`
CreateBy string `json:"createBy"`
CreateDate time.Time `json:"createDate"`
UpdateBy string `json:"updateBy"`
UpdateDate time.Time `json:"updateDate"`
}

参考文章

原文golang-gorm框架支持mysql json类型