gorm框架更新与删除
# 1,更新
# 1,更新所有字段
Save()
默认会更新该对象的所有字段,即使你没有赋值。
package main
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
// 1,定义模型
type User struct {
ID int64
Name string
Age int64
Active bool
}
func main() {
// 2, 连接数据库
db, err := gorm.Open("mysql", "root:root1234@(127.0.0.1:13306)/db1?charset=utf8mb4&parseTime=True&loc=Local")
if err != nil {
panic(err)
}
defer db.Close()
// 默认情况下,gorm创建的表将会是结构体名称的复数形式,如果不想让它自动复数,可以加一下禁用
db.SingularTable(true)
// 3, 把模型与数据库中的表对应起来
db.AutoMigrate(&User{})
// 4, 创建
//u1 := User{Name: "eryajf", Age: 20, Active: true}
//db.Create(&u1)
//u2 := User{Name: "jinzhu", Age: 22, Active: false}
//db.Create(&u2)
// 5, 查询
var user User
db.First(&user)
fmt.Println(user)
// 6, 更新
user.Name = "二丫讲梵"
user.Age = 20
// save 默认会更新该对象的所有字段,即使没有赋值
db.Debug().Save(&user) //UPDATE `user` SET `name` = '二丫讲梵', `age` = 20, `active` = true WHERE `user`.`id` = 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
# 2,更新修改字段
如果你只希望更新指定字段,可以使用Update
或者Updates
package main
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
// 1,定义模型
type User struct {
ID int64
Name string
Age int64
Active bool
}
func main() {
// 2, 连接数据库
db, err := gorm.Open("mysql", "root:root1234@(127.0.0.1:13306)/db1?charset=utf8mb4&parseTime=True&loc=Local")
if err != nil {
panic(err)
}
defer db.Close()
// 默认情况下,gorm创建的表将会是结构体名称的复数形式,如果不想让它自动复数,可以加一下禁用
db.SingularTable(true)
// 3, 把模型与数据库中的表对应起来
db.AutoMigrate(&User{})
// 4, 创建
//u1 := User{Name: "eryajf", Age: 20, Active: true}
//db.Create(&u1)
//u2 := User{Name: "jinzhu", Age: 22, Active: false}
//db.Create(&u2)
// 5, 查询
var user User
db.First(&user)
fmt.Println(user)
// 6, 更新
// 更新单个属性,如果他有变化
db.Debug().Model(&user).Update("name", "hello") //UPDATE `user` SET `name` = 'hello' WHERE `user`.`id` = 1
// 根据给定的条件更新单个属性
db.Debug().Model(&user).Where("active = ?", true).Update("name", "hello") //UPDATE `user` SET `name` = 'hello' WHERE `user`.`id` = 1 AND ((active = true))
// 使用map 更新多个属性,只会更新其中有变化的属性
db.Debug().Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "active": "false"}) //UPDATE `user` SET `active` = true, `age` = 18, `name` = 'hello' WHERE `user`.`id` = 1
// 使用struct 更新多个属性,只会更新其中有变化且为非零值的字段
db.Debug().Model(&user).Updates(User{Name: "hello", Age: 23}) //UPDATE `user` SET `age` = 23, `name` = 'hello' WHERE `user`.`id` = 1
// 警告:当使用struct更新时,GORM只会更新那些非零值的字段
// 对于下面的操作,不会发生任何更新
db.Debug().Model(&user).Updates(User{Name: "", Age: 0, Active: false})
//db.Debug().Model(&user)
}
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
54
55
56
57
58
# 3,更新选定字段
如果你想更新或忽略某些字段,你可以使用 Select
,Omit
package main
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
// 1,定义模型
type User struct {
ID int64
Name string
Age int64
Active bool
}
func main() {
// 2, 连接数据库
db, err := gorm.Open("mysql", "root:root1234@(127.0.0.1:13306)/db1?charset=utf8mb4&parseTime=True&loc=Local")
if err != nil {
panic(err)
}
defer db.Close()
// 默认情况下,gorm创建的表将会是结构体名称的复数形式,如果不想让它自动复数,可以加一下禁用
db.SingularTable(true)
// 3, 把模型与数据库中的表对应起来
db.AutoMigrate(&User{})
// 4, 创建
//u1 := User{Name: "eryajf", Age: 20, Active: true}
//db.Create(&u1)
//u2 := User{Name: "jinzhu", Age: 22, Active: false}
//db.Create(&u2)
// 5, 查询
var user User
db.First(&user)
fmt.Println(user)
// 6, 更新
m1 := map[string]interface{}{
"name": "liqilong",
"age": 20,
"active": true,
}
// 选择 m1 中某个字段进行更新
db.Debug().Model(&user).Select("name").Updates(m1) //UPDATE `user` SET `name` = 'liqilong' WHERE `user`.`id` = 1
// 忽略 m1 中active字段更新其他字段
db.Debug().Model(&user).Omit("active").Updates(m1) //UPDATE `user` SET `age` = 20, `name` = 'liqilong' WHERE `user`.`id` = 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
# 4,无 Hooks 更新
上面的更新操作会自动运行 model 的 BeforeUpdate
, AfterUpdate
方法,更新 UpdatedAt
时间戳, 在更新时保存其 Associations
, 如果你不想调用这些方法,你可以使用 UpdateColumn
, UpdateColumns
package main
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
// 1,定义模型
type User struct {
ID int64
Name string
Age int64
Active bool
}
func main() {
// 2, 连接数据库
db, err := gorm.Open("mysql", "root:root1234@(127.0.0.1:13306)/db1?charset=utf8mb4&parseTime=True&loc=Local")
if err != nil {
panic(err)
}
defer db.Close()
// 默认情况下,gorm创建的表将会是结构体名称的复数形式,如果不想让它自动复数,可以加一下禁用
db.SingularTable(true)
// 3, 把模型与数据库中的表对应起来
db.AutoMigrate(&User{})
// 4, 创建
//u1 := User{Name: "eryajf", Age: 20, Active: true}
//db.Create(&u1)
//u2 := User{Name: "jinzhu", Age: 22, Active: false}
//db.Create(&u2)
// 5, 查询
var user User
db.First(&user)
fmt.Println(user)
// 6, 更新
// 更新单个属性,类似于 update
db.Debug().Model(&user).UpdateColumn("name", "hello") //UPDATE `user` SET `name` = 'hello' WHERE `user`.`id` = 1
// 更新多个属性,类似于 updates
db.Debug().Model(&user).UpdateColumns(User{Name: "hello", Age: 18}) //UPDATE `user` SET `age` = 18, `name` = 'hello' WHERE `user`.`id` = 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
# 5,批量更新
批量更新时Hooks(钩子函数)
不会运行。
package main
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
// 1,定义模型
type User struct {
ID int64
Name string
Age int64
Active bool
}
func main() {
// 2, 连接数据库
db, err := gorm.Open("mysql", "root:root1234@(127.0.0.1:13306)/db1?charset=utf8mb4&parseTime=True&loc=Local")
if err != nil {
panic(err)
}
defer db.Close()
// 默认情况下,gorm创建的表将会是结构体名称的复数形式,如果不想让它自动复数,可以加一下禁用
db.SingularTable(true)
// 3, 把模型与数据库中的表对应起来
db.AutoMigrate(&User{})
// 4, 创建
//u1 := User{Name: "eryajf", Age: 20, Active: true}
//db.Create(&u1)
//u2 := User{Name: "jinzhu", Age: 22, Active: false}
//db.Create(&u2)
// 5, 查询
var user User
db.First(&user)
fmt.Println(user)
// 6, 更新
db.Debug().Table("user").Where("id IN (?)", []int{10, 11}).Updates(map[string]interface{}{"name": "hello", "age": 20}) //UPDATE `user` SET `age` = 20, `name` = 'hello' WHERE (id IN (10,11))
// 使用struct更新时,只会更新非零值字段,若想更新所有字段,应使用如上map方式
db.Debug().Model(User{}).Updates(User{Name: "hello", Age: 23}) //UPDATE `user` SET `age` = 23, `name` = 'hello'
// 使用 RowsAffected 获取更新记录总数
chageNum := db.Debug().Model(User{}).Updates(User{Name: "hello", Age: 23}).RowsAffected //UPDATE `user` SET `age` = 23, `name` = 'hello'
fmt.Println(chageNum)
//db.Debug().Model(&user)
}
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
# 6,使用 SQL 表达式更新
先查询表中的第一条数据保存至 user 变量。
package main
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
// 1,定义模型
type User struct {
ID int64
Name string
Age int64
Active bool
}
func main() {
// 2, 连接数据库
db, err := gorm.Open("mysql", "root:root1234@(127.0.0.1:13306)/db1?charset=utf8mb4&parseTime=True&loc=Local")
if err != nil {
panic(err)
}
defer db.Close()
// 默认情况下,gorm创建的表将会是结构体名称的复数形式,如果不想让它自动复数,可以加一下禁用
db.SingularTable(true)
// 3, 把模型与数据库中的表对应起来
db.AutoMigrate(&User{})
// 4, 创建
//u1 := User{Name: "eryajf", Age: 20, Active: true}
//db.Create(&u1)
//u2 := User{Name: "jinzhu", Age: 22, Active: false}
//db.Create(&u2)
// 5, 查询
var user User
db.First(&user)
fmt.Println(user)
// 6, 更新
// 给匹配到的用户增加3岁
db.Debug().Model(&user).Update("age", gorm.Expr("age + ?", 3)) //UPDATE `user` SET `age` = age + 3 WHERE `user`.`id` = 1
// 以map的方式进行年龄运算
db.Debug().Model(&user).Updates(map[string]interface{}{"age": gorm.Expr("age * ? + ?", 2, 100)}) //UPDATE `user` SET `age` = age * 2 + 100 WHERE `user`.`id` = 1
// 年龄减法
db.Debug().Model(&user).UpdateColumn("age", gorm.Expr("age - ?", "2")) //UPDATE `user` SET `age` = age - '2' WHERE `user`.`id` = 1
// 给符合查询条件的用户年龄-1
db.Debug().Model(&user).Where("age > 10").UpdateColumn("age", gorm.Expr("age - ?", 1)) //UPDATE `user` SET `age` = age - 1 WHERE `user`.`id` = 1 AND ((age > 10))
}
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
# 7,修改 Hooks 中的值
如果你想修改 BeforeUpdate
, BeforeSave
等 Hooks 中更新的值,你可以使用 scope.SetColumn
, 例如:
func (user *User) BeforeSave(scope *gorm.Scope) (err error) {
if pw, err := bcrypt.GenerateFromPassword(user.Password, 0); err == nil {
scope.SetColumn("EncryptedPassword", pw)
}
}
2
3
4
5
# 8,其它更新选项
// 为 update SQL 添加其它的 SQL
db.Model(&user).Set("gorm:update_option", "OPTION (OPTIMIZE FOR UNKNOWN)").Update("name", "hello")
//// UPDATE users SET name='hello', updated_at = '2013-11-17 21:34:10' WHERE id=111 OPTION (OPTIMIZE FOR UNKNOWN);
2
3
# 2,删除
# 1,删除记录
警告 删除记录时,请确保主键字段有值,GORM 会通过主键去删除记录,如果主键为空,GORM 会删除该 model 的所有记录。
// 删除现有记录
db.Delete(&email)
//// DELETE from emails where id=10;
// 为删除 SQL 添加额外的 SQL 操作
db.Set("gorm:delete_option", "OPTION (OPTIMIZE FOR UNKNOWN)").Delete(&email)
//// DELETE from emails where id=10 OPTION (OPTIMIZE FOR UNKNOWN);
2
3
4
5
6
7
# 2,批量删除
删除全部匹配的记录
package main
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
// 定义模型
type User struct {
gorm.Model
Name string
Age int64
Active bool
}
func main() {
db, err := gorm.Open("mysql", "root:root1234@(127.0.0.1:13306)/db1?charset=utf8mb4&parseTime=True&loc=Local")
if err != nil {
panic(err)
}
defer db.Close()
// 默认情况下,gorm创建的表将会是结构体名称的复数形式,如果不想让它自动复数,可以加一下禁用
db.SingularTable(true)
// 2, 把模型与数据库中的表对应起来
db.AutoMigrate(&User{})
// 3, 创建
//u1 := User{Name: "eryajf", Age: 20, Active: true}
// //db.Create(&u1)
// //u2 := User{Name: "jinzhu", Age: 22, Active: false}
// //db.Create(&u2)
// //u3 := User{Name: "eryajf2", Age: 20, Active: true}
// //db.Create(&u3)
// //u4 := User{Name: "jinzhu2", Age: 22, Active: false}
// //db.Create(&u4)
// 删除符合条件的记录
db.Debug().Where("name LIKE ?", "%jinzhu%").Delete(User{}) //UPDATE `user` SET `deleted_at`='2020-03-08 23:48:05' WHERE `user`.`deleted_at` IS NULL AND ((name LIKE 'jinzhu'))
// 与上边效果一样
db.Debug().Delete(User{}, "name LIKE ?", "%jinzhu%") //UPDATE `user` SET `deleted_at`='2020-03-08 23:49:34' WHERE `user`.`deleted_at` IS NULL AND ((name LIKE '%jinzhu%'))
}
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
# 3,软删除
如果一个 model 有 DeletedAt
字段,他将自动获得软删除的功能! 当调用 Delete
方法时, 记录不会真正的从数据库中被删除, 只会将DeletedAt
字段的值会被设置为当前时间
db.Delete(&user)
//// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;
// 批量删除
db.Where("age = ?", 20).Delete(&User{})
//// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;
// 查询记录时会忽略被软删除的记录
db.Where("age = 20").Find(&user)
//// SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;
// Unscoped 方法可以查询被软删除的记录
db.Unscoped().Where("age = 20").Find(&users)
//// SELECT * FROM users WHERE age = 20;
2
3
4
5
6
7
8
9
10
11
12
13
14
# 4,物理删除
// Unscoped 方法可以物理删除记录
db.Unscoped().Delete(&order)
//// DELETE FROM orders WHERE id=10;
2
3
代码示例:
package main
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
// 定义模型
type User struct {
gorm.Model
Name string
Age int64
Active bool
}
func main() {
db, err := gorm.Open("mysql", "root:root1234@(127.0.0.1:13306)/db1?charset=utf8mb4&parseTime=True&loc=Local")
if err != nil {
panic(err)
}
defer db.Close()
// 默认情况下,gorm创建的表将会是结构体名称的复数形式,如果不想让它自动复数,可以加一下禁用
db.SingularTable(true)
// 2, 把模型与数据库中的表对应起来
db.AutoMigrate(&User{})
// 3, 创建
//u1 := User{Name: "eryajf", Age: 20, Active: true}
// //db.Create(&u1)
// //u2 := User{Name: "jinzhu", Age: 22, Active: false}
// //db.Create(&u2)
// //u3 := User{Name: "eryajf2", Age: 20, Active: true}
// //db.Create(&u3)
// //u4 := User{Name: "jinzhu2", Age: 22, Active: false}
// //db.Create(&u4)
// 批量删除
db.Debug().Where("age = ?", 20).Delete(&User{}) //UPDATE `user` SET `deleted_at`='2020-03-08 23:53:03' WHERE `user`.`deleted_at` IS NULL AND ((age = 20))
// 查询记录时会忽略被软删除的记录
var user User
db.Debug().Where("age = 20").Find(&user) //SELECT * FROM `user` WHERE `user`.`deleted_at` IS NULL AND ((age = 20))
fmt.Println(user)
// Unscoped 方法可以查询被软删除的记录
db.Debug().Unscoped().Where("age = 20").Find(&user) //SELECT * FROM `user` WHERE (age = 20)
fmt.Println(user)
// Unscoped 方法可以物理删除记录
db.Debug().Unscoped().Delete(User{}, "name = ?", "eryajf") //DELETE FROM `user` WHERE (name = 'eryajf')
}
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
# 3,链式操作相关
# 1,链式操作
Method Chaining,Gorm 实现了链式操作接口,所以你可以把代码写成这样:
// 创建一个查询
tx := db.Where("name = ?", "jinzhu")
// 添加更多条件
if someCondition {
tx = tx.Where("age = ?", 20)
} else {
tx = tx.Where("age = ?", 30)
}
if yetAnotherCondition {
tx = tx.Where("active = ?", 1)
}
2
3
4
5
6
7
8
9
10
11
12
13
在调用立即执行方法前不会生成Query
语句,借助这个特性你可以创建一个函数来处理一些通用逻辑。
# 2,立即执行方法
Immediate methods ,立即执行方法是指那些会立即生成SQL
语句并发送到数据库的方法, 他们一般是CRUD
方法,比如:
Create
, First
, Find
, Take
, Save
, UpdateXXX
, Delete
, Scan
, Row
, Rows
…
这有一个基于上面链式方法代码的立即执行方法的例子:
tx.Find(&user)
生成的 SQL 语句如下:
SELECT * FROM users where name = 'jinzhu' AND age = 30 AND active = 1;
# 3,范围
Scopes
,Scope 是建立在链式操作的基础之上的。
基于它,你可以抽取一些通用逻辑,写出更多可重用的函数库。
func AmountGreaterThan1000(db *gorm.DB) *gorm.DB {
return db.Where("amount > ?", 1000)
}
func PaidWithCreditCard(db *gorm.DB) *gorm.DB {
return db.Where("pay_mode_sign = ?", "C")
}
func PaidWithCod(db *gorm.DB) *gorm.DB {
return db.Where("pay_mode_sign = ?", "C")
}
func OrderStatus(status []string) func (db *gorm.DB) *gorm.DB {
return func (db *gorm.DB) *gorm.DB {
return db.Scopes(AmountGreaterThan1000).Where("status IN (?)", status)
}
}
db.Scopes(AmountGreaterThan1000, PaidWithCreditCard).Find(&orders)
// 查找所有金额大于 1000 的信用卡订单
db.Scopes(AmountGreaterThan1000, PaidWithCod).Find(&orders)
// 查找所有金额大于 1000 的 COD 订单
db.Scopes(AmountGreaterThan1000, OrderStatus([]string{"paid", "shipped"})).Find(&orders)
// 查找所有金额大于 1000 且已付款或者已发货的订单
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
# 4,多个立即执行方法
Multiple Immediate Methods,在 GORM 中使用多个立即执行方法时,后一个立即执行方法会复用前一个立即执行方法的条件 (不包括内联条件) 。
db.Where("name LIKE ?", "jinzhu%").Find(&users, "id IN (?)", []int{1, 2, 3}).Count(&count)
生成的 Sql
SELECT * FROM users WHERE name LIKE 'jinzhu%' AND id IN (1, 2, 3)
SELECT count(*) FROM users WHERE name LIKE 'jinzhu%'
2
3