Go gorm| MySQL不支持数组/切片怎么办?

5,503 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情

🎐 放在前面说的话

大家好,我是北 👧🏻

本科在读,此为日常捣鼓.

如有不对,请多指教,也欢迎大家来跟我讨论鸭 👏👏👏

还有还有还有很重要的,麻烦大可爱们动动小手,给北点颗心心♥,北北需要鼓励嗷呜~

今天我们来浅谈一下代码过程中遇到直接定义model数组/切片类型,存不进MySQL数据库怎么办?怎么解决?

image.png

Let’s get it!

出现问题:

在使用gorm包定义的数据库的结构如下:

type Todo struct {
	gorm.Model
	UID      uint   // 用户 ID
	Title    string `json:"title"  binding:"min=1,max=64"`    // 文章标题
	Content  string `json:"content"  binding:"min=1,max=512"` // 内容
	Tag      []string    `json:"tag"  binding:"required"`          // 标签
	Deadline uint   `json:"deadline"`                         // 截止时间
}

go run 时,报错(sql: converting argument $1 type: unsupported type []string, a slice of string

分析原因:

mysql中不支持[]string 类型的数据,不可以直接在结构体中定义[]string类型。

解决方案

基于gorm 库的特性,可以通过自定义JSON类型将数据传入,因此解决步骤一共分为两步:

  • step 1:将[]string类型编码为JSON类型数据;
  • step 2:自定义JSON类型数据,使得gorm可以支持,可以参考GORM-自定义数据类型

step 1: 首先将结构体中数据类型定义改为一个新的自定义类型

type Tag []string

/**
 * @description: todos 数据表
 */
type Todo struct {
	gorm.Model
	UID      uint   // 用户 ID
	Title    string `json:"title"  binding:"min=1,max=64"`    // 文章标题
	Content  string `json:"content"  binding:"min=1,max=512"` // 内容
	Tag      Tag    `json:"tag"  binding:"required"`          // 标签
	Deadline uint   `json:"deadline"`                         // 截止时间
}

step 2:自定义一个JSON类型,可以参考GORM-自定义数据类型

我们 step 1把Tag自定义为type Tag []string,但是这种类型在gorm中还不可以直接识别,所以需要进一步自定义数据类型。

func (t *Tag) Scan(value interface{}) error {
	bytesValue, _ := value.([]byte)
	return json.Unmarshal(bytesValue, t)
}

func (t Tag) Value() (driver.Value, error) {
	return json.Marshal(t)
}
  • Scan()存入数据库前转为 string
  • Value()读出数据前转为 json 说白了就是,我们不是直接的把[]string类型的数据直接存入MySQL数据库,而是自定义成一个json类型,存储前,我们把它转为string,取出时,我们把转变为我们需要的json。(一共有3个步骤)就是这么一个简单的原理啦!

gorm官方文档中的自定义数据类型

GORM 提供了少量接口,让开发者能够自定义GORM 支持的数据类型

实现自定义数据类型由以下两个函数实现

  • Scan()
  • Value()

自定义的数据类型必须实现 Scanner 和 Valuer 接口,以便让 GORM 知道如何将该类型接收、保存到数据库

🎉 放在后面说的话

报错sql: converting argument $1 type: unsupported type []string, a slice of string怎么办?来,我们用gorm自定义数据类型来解决它。仅需ScannerValuer两个接口,便可把你想要的数组或切片类型存储进MySQL数据库!本文我从问题报错、分析原因、解决办法,拓展运用知识为你解愁~