Gorm复合主键(联合主键)使用时需要注意的点

当我在使用Go语言开发时,使用MySQL数据库,gorm框架,遇到了一些小坑,在这里给自己一个记录,也给各位道友普及一下我掉过的坑,有类似的可以借鉴一下。
在使用gorm时,会有这样的需求:
我想要存储数据,这条数据如果在数据库中存在,就做更新操作;如果不存在就做插入操作。
而gorm就提供了很好的封装——Save方法。
我们来看看官方文档怎么说这个Save的:

1.4.1. 更新全部字段
Save将包括执行更新SQL时的所有字段,即使它没有更改

直接说一个拓展的应用吧,基础应用就照猫画虎即可。
应用场景:用户的关注其他用户功能。单独维护一张关注表,可用来查找是否互相关注。
不论是关注者ID还是被关注者ID都不适合做主键,因为一个用户可被多个用户关注,一个用户可关注多个其他用户。
于是定义结构:

type UserFollow struct {
	ID         int64  `json:"id" gorm:"primary_key"`
	AccountID  int64  `json:"account_id"`				//被关注者ID
	FollowerID int64  `json:"follower_id"`				//关注者ID
	Status     STATUS `json:"status" gorm:"default:1"`	//是否有效
}

写入数据库代码:

f := new(UserFollow )
f.AccountID = 1
f.FollowerID = 2
f.Status = 1
db.NewConn().Model(f).Save(&f)

然而并没有实现有记录则更新的操作,一直在添加新的数据。这是为什么呢?
其实,这是因为,当你在使用Save 的时候,如果Save的对象包含主键,则能实现有记录则更新,无记录则插入;当对象不包含主键,则只有插入功能。 但是ID主键如果想要获取,那必须要查询一次数据库,既然查询数据库了,那还用Save干嘛。
既然单独的一个ID不能做主键,但是“我关注你”这样的一个状态,在表中的体现只可能是一条,于是想到了复合主键(联合主键、组合主键,个人爱怎么叫怎么叫吧),官方给出的文档:

1.5. 复合主键
将多个字段设置为主键以启用复合主键

type Product struct {
    ID           string `gorm:"primary_key"`
    LanguageCode string `gorm:"primary_key"`
}

很好,简单明了,开搞:

type UserFollow struct {
	AccountID  int64  `json:"account_id"  gorm:"primary_key"`
	FollowerID int64  `json:"follower_id"  gorm:"primary_key"`
	Status     STATUS `json:"status" gorm:"default:1"`
}

编译生成表:

if err := dbExPool.NewConn().AutoMigrate(
		new(domain.UserFollow),
	).Error; err != nil {
		loggers.Error.Printf("Exchange DB auto migrate error %s", err.Error())
		return
	}

直接报错:

[2020-04-26 11:55:42]  [35.15ms]  CREATE TABLE `user_follows` (`account_id` bigint AUTO_INCREMENT,`follower_id` bigint AUTO_INCREMENT,`status` int DEFAULT 1 , PRIMARY KEY (`account_id`,`follower_id`))  
[0 rows affected or returned ] 
[ERROR] 2020/04/26 11:55:42 main.go:34: Exchange DB auto migrate error Error 1075: Incorrect table definition; there can be only one auto column and it must be defined as a key

“Error 1075: Incorrect table definition; there can be only one auto column and it must be defined as a key”
错误指出:只能有一项自动增长列!
注意看报错第一行的sql语句,我们设置的两个PRIMARY KEY都是“AUTO_INCREMENT”,这是因为,当没有指定的时候,gorm自动帮我们认定,主键int类为自动增长。所以需要我们手动更改,指定转化的sql语句 sql:"type:INT(10) UNSIGNED NOT NULL"

type UserFollow struct {
	AccountID  int64  `json:"account_id" gorm:"primary_key" sql:"type:INT(10) UNSIGNED NOT NULL"`
	FollowerID int64  `json:"follower_id" gorm:"primary_key" sql:"type:INT(10) UNSIGNED NOT NULL"`
	Status     STATUS `json:"status" gorm:"default:1"`
}

这时再生成表:

[2020-04-26 12:02:36]  [392.48ms]  CREATE TABLE `user_follows` (`account_id` INT(10) UNSIGNED NOT NULL,`follower_id` INT(10) UNSIGNED NOT NULL,`status` int DEFAULT 1 , PRIMARY KEY (`account_id`,`follower_id`))  
[0 rows affected or returned ] 

Process finished with exit code 0

搞定!

你可能感兴趣的:(Gorm复合主键(联合主键)使用时需要注意的点)