db.Save(&User{ID: 1, Name: "jinzhu", Age: 100}) // UPDATE `users` SET `name`="jinzhu",`age`=100,`birthday`="0000-00-00 00:00:00",`update_at`="0000-00-00 00:00:00" WHERE `id` = 1
NOTE不要将 Save 和 Model一同使用, 这是 未定义的行为。
更新单个列
当使用 Update 更新单列时,需要有一些条件,否则将会引起ErrMissingWhereClause 错误,查看 阻止全局更新 了解详情。 当使用 Model 方法,并且它有主键值时,主键将会被用于构建条件,例如:
// 根据条件更新 db.Model(&User{}).Where("active = ?", true).Update("name", "hello") // UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE active=true;
// User 的 ID 是 `111` db.Model(&user).Update("name", "hello") // UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111;
// 根据条件和 model 的值进行更新 db.Model(&user).Where("active = ?", true).Update("name", "hello") // UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111 AND active=true;
func(u *User) BeforeUpdate(tx *gorm.DB) (err error) { if u.Role == "admin" { return errors.New("admin user not allowed to update") } return }
批量更新
If we haven’t specified a record having a primary key value with Model, GORM will perform a batch update
// Update with struct db.Model(User{}).Where("role = ?", "admin").Updates(User{Name: "hello", Age: 18}) // UPDATE users SET name='hello', age=18 WHERE role = 'admin';
// Update with map db.Table("users").Where("id IN ?", []int{10, 11}).Updates(map[string]interface{}{"name": "hello", "age": 18}) // UPDATE users SET name='hello', age=18 WHERE id IN (10, 11);
阻止全局更新
If you perform a batch update without any conditions, GORM WON’T run it and will return ErrMissingWhereClause error by default
You have to use some conditions or use raw SQL or enable the AllowGlobalUpdate mode, for example:
db.Model(&User{}).Where("1 = 1").Update("name", "jinzhu") // UPDATE users SET `name` = "jinzhu" WHERE 1=1
db.Exec("UPDATE users SET name = ?", "jinzhu") // UPDATE users SET name = "jinzhu"
db.Session(&gorm.Session{AllowGlobalUpdate: true}).Model(&User{}).Update("name", "jinzhu") // UPDATE users SET `name` = "jinzhu"
更新的记录数
Get the number of rows affected by a update
// Get updated records count with `RowsAffected` result := db.Model(User{}).Where("role = ?", "admin").Updates(User{Name: "hello", Age: 18}) // UPDATE users SET name='hello', age=18 WHERE role = 'admin';
db.Model(&User{ID: 1}).Updates(User{ Name: "jinzhu", Location: Location{X: 100, Y: 100}, }) // UPDATE `user_with_points` SET `name`="jinzhu",`location`=ST_PointFromText("POINT(100 100)") WHERE `id` = 1
根据子查询进行更新
Update a table by using SubQuery
db.Model(&user).Update("company_name", db.Model(&Company{}).Select("name").Where("companies.id = users.company_id")) // UPDATE "users" SET "company_name" = (SELECT name FROM companies WHERE companies.id = users.company_id);
db.Table("users as u").Where("name = ?", "jinzhu").Update("company_name", db.Table("companies as c").Select("name").Where("c.id = u.company_id"))
db.Table("users as u").Where("name = ?", "jinzhu").Updates(map[string]interface{}{"company_name": db.Table("companies as c").Select("name").Where("c.id = u.company_id")})
不使用 Hook 和时间追踪
If you want to skip Hooks methods and don’t track the update time when updating, you can use UpdateColumn, UpdateColumns, it works like Update, Updates
// Update single column db.Model(&user).UpdateColumn("name", "hello") // UPDATE users SET name='hello' WHERE id = 111;
// Update multiple columns db.Model(&user).UpdateColumns(User{Name: "hello", Age: 18}) // UPDATE users SET name='hello', age=18 WHERE id = 111;
// Update selected columns db.Model(&user).Select("name", "age").UpdateColumns(User{Name: "hello", Age: 0}) // UPDATE users SET name='hello', age=0 WHERE id = 111;
返回修改行的数据
Returning changed data only works for databases which support Returning, for example:
// return all columns var users []User db.Model(&users).Clauses(clause.Returning{}).Where("role = ?", "admin").Update("salary", gorm.Expr("salary * ?", 2)) // UPDATE `users` SET `salary`=salary * 2,`updated_at`="2021-10-28 17:37:23.19" WHERE role = "admin" RETURNING * // users => []User{{ID: 1, Name: "jinzhu", Role: "admin", Salary: 100}, {ID: 2, Name: "jinzhu.2", Role: "admin", Salary: 1000}}
GORM provides the Changed method which could be used in Before Update Hooks, it will return whether the field has changed or not.
The Changed method only works with methods Update, Updates, and it only checks if the updating value from Update / Updates equals the model value. It will return true if it is changed and not omitted
func(u *User) BeforeUpdate(tx *gorm.DB) (err error) { // if Role changed if tx.Statement.Changed("Role") { return errors.New("role not allowed to change") }
if tx.Statement.Changed("Name", "Admin") { // if Name or Role changed tx.Statement.SetColumn("Age", 18) }
// if any fields changed if tx.Statement.Changed() { tx.Statement.SetColumn("RefreshedAt", time.Now()) } returnnil }