当前位置: 首页 > news >正文

Gorm学习笔记 - CRUD记要

教程地址:https://www.kancloud.cn/sliver_horn/gorm/1861154
上一篇:https://blog.csdn.net/qq_17523181/article/details/152366210?spm=1011.2415.3001.5331

一、模型定义

1. 字段级权限控制
type User struct {Name string `gorm:"<-:create"` // 允许读和创建Name string `gorm:"<-:update"` // 允许读和更新Name string `gorm:"<-"`        // 允许读和写(创建和更新)Name string `gorm:"<-:false"`  // 允许读,禁止写Name string `gorm:"->"`        // 只读(除非有自定义配置,否则禁止写)Name string `gorm:"->;<-:create"` // 允许读和写Name string `gorm:"->:false;<-:create"` // 仅创建(禁止从 db 读)Name string `gorm:"-"`  // 读写操作均会忽略该字段
}
2. 创建/更新时间追踪(纳秒、毫秒、秒、Time)
type User struct {CreatedAt time.Time // 在创建时,如果该字段值为零值,则使用当前时间填充UpdatedAt int       // 在创建时该字段值为零值或者在更新时,使用当前秒级时间戳填充Updated   int64 `gorm:"autoUpdateTime:nano"` // 使用纳秒级时间戳填充更新时间Updated   int64 `gorm:"autoUpdateTime:milli"` // 使用毫秒级时间戳填充更新时间Created   int64 `gorm:"autoCreateTime"`      // 使用秒级时间戳填充创建时间
}
3. 通过标签 embedded 将其嵌入,例如使用embedded后,可以Blog.Name,本来要使用Blog.Author.Name
type Author struct {Name  stringEmail string
}type Blog struct {ID      intAuthor  Author `gorm:"embedded"`Upvotes int32
}
// 等效于
type Blog struct {ID    int64Name  stringEmail stringUpvotes  int32
}
4. 可以使用标签 embeddrefix 来为 db 中的字段名添加前缀
type Blog struct {ID      intAuthor  Author `gorm:"embedded;embeddedPrefix:author_"`Upvotes int32
}
// 等效于
type Blog struct {ID          int64AuthorName  stringAuthorEmail stringUpvotes     int32
}
5. 标签名说明
标签名说明
column指定 db 列名
type列数据类型,推荐使用兼容性好的通用类型,例如:bool、int、uint、float、string、time、bytes。
并可与其他标签一起使用,例如:not null、size, autoIncrement… 像 varbinary(8) 这样指定数据库数据类型也是支持的。
在使用指定数据库数据类型时,它需要是完整的数据库数据类型,如:MEDIUMINT UNSINED not NULL AUTO_INSTREMENT
size指定列大小,例如:size:256
unique指定列为唯一
primaryKey指定列为主键
default指定列的默认值
precision指定列的精度
not null指定列为 NOT NULL
autoIncrement指定列为自动增长
embedded嵌套字段
embeddedPrefix嵌套字段的前缀
autoCreateTime创建时追踪当前时间,对于 int 字段,它会追踪秒级时间戳,您可以使用 nano/milli 来追踪纳秒、毫秒时间戳,
例如:autoCreateTime:nano
autoUpdateTime创建/更新时追踪当前时间,对于 int 字段,它会追踪秒级时间戳,您可以使用 nano/milli 来追踪纳秒、毫秒时间戳,
例如:autoUpdateTime:milli
index根据参数创建索引,多个字段拥有相同的名称则创建复合索引,参考 索引 获取详情
uniqueIndex与 index 相同,但创建的是唯一索引
check创建检查约束,例如 check:(age > 13),查看 约束 获取详情
<-设置字段写入的权限, <-:create 只创建、<-:update 只更新、<-:false 无权限
->设置字段读取权限
-忽略此字段(禁止读写)

二、创建

1. 创建钩子

GORM 允许 BeforeSave, BeforeCreate, AfterSave, AfterCreate 等钩子,创建记录时会调用这些方法

func (u *User) BeforeCreate(tx *gorm.DB) (err error) {u.UUID = uuid.New()if u.Role == "admin" {return errors.New("invalid role")}return
}
2. 批量插入

将切片数据传递给 Create 方法,GORM 将生成一个单一的 SQL 语句来插入所有数据,并回填主键的值,钩子方法也会被调用。

var users = []User{{Name: "jinzhu1"}, {Name: "jinzhu2"}, {Name: "jinzhu3"}}
DB.Create(&users)for _, user := range users {user.ID // 1,2,3
}
3. 关联创建与跳过关联

如果您的模型定义了任何关系(relation),并且它有非零关系,那么在创建时这些数据也会被保存

type CreditCard struct {gorm.ModelNumber   stringUserID   uint
}type User struct {gorm.ModelName       stringCreditCard CreditCard
}db.Create(&User{Name: "jinzhu",CreditCard: CreditCard{Number: "411111111111"}
})
// INSERT INTO `users` ...
// INSERT INTO `credit_cards` ...

您也可以通过 Omit 跳过关联保存

db.Omit("CreditCard").Create(&user)// 跳过所有关联
db.Omit(clause.Associations).Create(&user)

三、查询

1. GORM 提供 First, Take, Last 方法,以便从数据库中检索单个对象。
2. Distinct

从模型中选择不相同的值

db.Distinct("name", "age").Order("name, age desc").Find(&results)
3. Locking (FOR UPDATE)

GORM 支持多种类型的锁,

作用:
排他锁(FOR UPDATE)是悲观锁的一种实现,它会锁定查询到的所有行,防止其他事务对这些行进行更新或删除操作(其他事务仍可读取数据)。锁会在当前事务提交或回滚时自动释放。

应用场景​:
主要用于需要强一致性的并发操作,例如电商系统中的库存扣减、资金转账等场景。例如,在用户下单时,需要先锁定商品库存记录,防止其他用户同时下单导致超卖

例如:

DB.Clauses(clause.Locking{Strength: "UPDATE"}).Find(&users)
// SELECT * FROM `users` FOR UPDATEDB.Clauses(clause.Locking{Strength: "SHARE",Table: clause.Table{Name: clause.CurrentTable},
}).Find(&users)
// SELECT * FROM `users` FOR SHARE OF `users`
4. 一些高级查询
  • FirstOrInit
    获取第一条匹配的记录,或者根据给定的条件初始化一个 struct(仅支持 sturct 和 map 条件)
  • FirstOrCreate
    获取第一条匹配的记录,或者根据给定的条件创建一条新纪录(仅支持 sturct 和 map 条件)
  • 查询钩子
    对于查询操作,GORM 支持 AfterFind 钩子,查询记录后会调用它
func (u *User) AfterFind(tx *gorm.DB) (err error) {if u.Role == "" {u.Role = "user"}return
}
5. Pluck

Pluck 用于从数据库查询单个列,并将结果扫描到切片。如果您想要查询多列,您应该使用 Scan

6. Scopes

Scopes 允许你指定常用的查询,可以在调用方法时引用这些查询

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.Where("status IN (?)", status)}
}db.Scopes(AmountGreaterThan1000, PaidWithCreditCard).Find(&orders)
// 查找所有金额大于 1000 的信用卡订单db.Scopes(AmountGreaterThan1000, PaidWithCod).Find(&orders)
// 查找所有金额大于 1000 的货到付款订单db.Scopes(AmountGreaterThan1000, OrderStatus([]string{"paid", "shipped"})).Find(&orders)
// 查找所有金额大于 1000 且已付款或已发货的订单

四、更新

1. 更新钩子

对于更新操作,GORM 支持 BeforeSave、BeforeUpdate、AfterSave、AfterUpdate 钩子,这些方法将在更新记录时被调用

func (u *User) BeforeUpdate(tx *gorm.DB) (err error) {if u.Role == "admin" {return errors.New("admin user not allowed to update")}return
}
2. 阻止全局更新

如果在没有任何条件的情况下执行批量更新,GORM 不会执行该操作,并返回ErrMissingWhereClause错误
您可以使用 = 之类的条件来强制全局更新

db.Model(&User{}).Update("name", "jinzhu").Error // gorm.ErrMissingWhereClausedb.Model(&User{}).Where("1 = 1").Update("name", "jinzhu")
// UPDATE users SET `name` = "jinzhu" WHERE 1=1
3. 更新的记录数
// 通过 `RowsAffected` 得到更新的记录数
result := db.Model(User{}).Where("role = ?", "admin").Updates(User{Name: "hello", Age: 18})
// UPDATE users SET name='hello', age=18 WHERE role = 'admin;result.RowsAffected // 更新的记录数
result.Error        // 更新的错误

五、删除

1. 删除钩子

对于删除操作,GORM 支持 BeforeDelete、AfterDelete 钩子,在删除记录时会调用这些方法

func (u *User) BeforeDelete(tx *gorm.DB) (err error) {if u.Role == "admin" {return errors.New("admin user not allowed to delete")}return
}
2. 阻止全局删除

如果在没有任何条件的情况下执行批量删除,GORM 不会执行该操作,并返回ErrMissingWhereClause错误
您可以使用 = 之类的条件来强制全局删除

db.Delete(&User{}).Error // gorm.ErrMissingWhereClausedb.Where("1 = 1").Delete(&User{})
// DELETE `users` WHERE 1=1
3. 软删除

如果您的模型包含了一个 gorm.deletedat 字段(gorm.Model 已经包含了该字段),它将自动获得软删除的能力!
拥有软删除能力的模型调用 Delete 时,记录不会被数据库。但 GORM 会将 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;

如果您不想引入 gorm.Model,您也可以这样启用软删除特性:

type User struct {ID      intDeleted gorm.DeletedAtName    string
}
4. 查找被软删除的记录

您可以使用 Unscoped 找到被软删除的记录

db.Unscoped().Where("age = 20").Find(&users)
// SELECT * FROM users WHERE age = 20;
5. 永久删除

您也可以使用 Unscoped 永久删除匹配的记录

db.Unscoped().Delete(&order)
// DELETE FROM orders WHERE id=10;

六、SQL 构建器

1. 原生 SQL 查询
type Result struct {ID   intName stringAge  int
}var result Result
db.Raw("SELECT id, name, age FROM users WHERE name = ?", 3).Scan(&result)db.Raw("SELECT id, name, age FROM users WHERE name = ?", 3).Scan(&result)var age int
DB.Raw("select sum(age) from users where role = ?", "admin").Scan(&age)
2. 执行原生 SQL
db.Exec("DROP TABLE users")
db.Exec("UPDATE orders SET shipped_at=? WHERE id IN ?", time.Now(), []int64{1,2,3})// SQL 表达式
DB.Exec("update users set money=? where name = ?", gorm.Expr("money * ? + ?", 10000, 1), "jinzhu")
3. DryRun 模式

在不执行的情况下生成 SQL ,可以用于准备或测试生成的 SQL

stmt := DB.Session(&Session{DryRun: true}).First(&user, 1).Statement
stmt.SQL.String() //=> SELECT * FROM `users` WHERE `id` = $1 ORDER BY `id`
stmt.Vars         //=> []interface{}{1}
4. Clauses

GORM 内部使用 SQL builder 生成 SQL。对于每个操作,GORM 都会创建一个 *gorm.Statement 对象,所有的 GORM API 都是在为 statement 添加/修改 Clause,最后,GORM 会根据这些 Clause 生成 SQL

http://www.dtcms.com/a/454784.html

相关文章:

  • 参股长江存储(长存集团)的公司
  • 写作网站官方做房地产公司网站的费用
  • JAVA算法练习题day28
  • 如何在谷歌做网站外链网络公关的作用
  • 医院网站规划方案手机网站开发最好用的框架
  • 快速排名优化怎么样郑州企业网站优化服务哪家好
  • 公司网站 制作wordpress 关键词设置
  • 无锡做网站服务wordpress 4.5.2 编辑器插件
  • 营销型网站单页wordpress页面的添加
  • 做电脑租赁网站仿站怎么做
  • 做网站欢迎页什么意思最新网络营销方式
  • 网站单个页面301跳转专业网页制作多少钱
  • 有域名 如何免费建设网站广告制作公司如何开展业务
  • 网站制作软件都是什么软件网站快速刷排名工具
  • 网络建设网站服务专业建设
  • .net网站开发优点怎么发布个人网站
  • 四川住房和城乡建设厅网站不能打开蓝天使网站建设推广
  • 科技网站模板wordpress博客网站描述在哪里
  • 网站建设费应开具互联网信息服务吗wordpress访问加密
  • 购物网站图标域名和网站的区别
  • 234. 回文链表 LeetCode 热题 HOT 100
  • 淘宝网站建设可行性分析电子商务实现技术
  • 怎么做捐款网站更改wordpress前缀
  • snipaste免费版下载安装教程
  • 湖南网站设计外包费用wordpress批量添加tag
  • 郑州网站建设yipinpai枣庄网站开发招聘
  • 启动网站建设的请示115做网站
  • 网站运营案例巅云建站
  • 南宁做网站公司品牌云尚网络免费做团购网站的软件
  • 长春专业做网站公司排名一站式网站建设平台