Gorm V2的使用感受和Save方法
和v1对比
-
gorm-v2不支持多表情况下软硬删除的混合链式调用,否则会panic
-
gorm-v2的create如果在select后调用,会出现插入空值的情况,可以通过select().create或者用db.session来解决
https://github.com/go-gorm/gorm/issues/4778
-
gorm-v2不需要subQuery了
-
gorm-v2没有newScope方法来获取表名了
给我目前最大的方便:
- 可以进行批量插入了,且批量插入后能获取到对应的递增主键
Save的使用
由于业务需要用到不存在时插入,存在时更新的功能,于是就想到了Save方法。
使用save的前提
表中必须要指定主键。如果想要实现不存在插入,存在更新的功能,则传入参数有主键的情况一定要填上。
-
如果save传的是结构体,那么如果这条记录不存在他会执行三条sql
package dbtest var ( gdb *gorm.DB ) func init() { db, err := InitDBV2(false, false) if err != nil { log.Fatal("init db failed,err=" + err.Error()) } gdb = db if err = db.Set("gorm:table_options", "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;").AutoMigrate(&Recode{}); err != nil { log.Error("create table error ", err) return } } type Recode struct { FromWeb string `gorm:"primarykey"` Author string Title string Time string LinkUrl string Content string } func Test_save(t *testing.T) { db := gdb.Debug() r2 := Recode{ FromWeb: "10779", Author: "李四", Title: "Friday", } err := db.Save(&r2).Error if err != nil { t.Error("save failed,e=", err) return } }
sql执行记录:
2021/12/30 17:03:21 /root/code/test/db/db_test.go:104 [0.756ms] [rows:0] UPDATE `recodes` SET `author`='李四',`title`='Friday',`time`='',`link_url`='',`content`='' WHERE `from_web` = '10779' 2021/12/30 17:03:21 /root/code/test/db/db_test.go:104 [0.565ms] [rows:0] SELECT * FROM `recodes` WHERE `from_web` = '10779' LIMIT 1 2021/12/30 17:03:21 /root/code/test/db/db_test.go:104 [6.697ms] [rows:1] INSERT INTO `recodes` (`from_web`,`author`,`title`,`time`,`link_url`,`content`) VALUES ('10779','李四','Friday','','','') --- PASS: Test_save (0.01s)
-
如果用切片进行传参,则只会执行一条语句
func Test_save(t *testing.T) { db := gdb.Debug() r2 := Recode{ FromWeb: "10779", Author: "李四", Title: "Friday", } var rs = []Recode{r2} err := db.Save(&rs).Error if err != nil { t.Error("save failed,e=", err) return } }
sql执行记录:
2021/12/30 17:06:29 /root/code/test/db/db_test.go:104 [0.627ms] [rows:0] INSERT INTO `recodes` (`from_web`,`author`,`title`,`time`,`link_url`,`content`) VALUES ('10779','李四','Friday','','','') ON DUPLICATE KEY UPDATE `author`=VALUES(`author`),`title`=VALUES(`title`),`time`=VALUES(`time`),`link_url`=VALUES(`link_url`),`content`=VALUES(`content`)
因此建议如果是需要实现存在更新的场景,建议用切片传参
save 的选择性字段更新
-
如果我只想每次只更新某几个字段,其他字段不更新,有没有什么方法。毕竟save是会将0值或者空串都会更新到数据库中的。于是可以用到Select方法:
func Test_save(t *testing.T) { db := gdb.Debug() r2 := Recode{ FromWeb: "10779", Author: "李四", Title: "Friday", LinkUrl: "www.baidu.com", } var rs = []Recode{r2} //主键不要忘了填入select中 err := db.Select("from_web", "author", "title").Save(&rs).Error if err != nil { t.Error("save failed,e=", err) return } }
可以看到sql的执行记录
2021/12/30 17:12:23 /root/code/test/db/db_test.go:105 [1.028ms] [rows:0] INSERT INTO `recodes` (`from_web`,`author`,`title`) VALUES ('10779','李四','Friday') ON DUPLICATE KEY UPDATE `author`=VALUES(`author`),`title`=VALUES(`title`)