Gorm框架学习---CRUD接口之创建
Posted 大忽悠爱忽悠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gorm框架学习---CRUD接口之创建相关的知识,希望对你有一定的参考价值。
Gorm框架学习---CRUD接口之创建
本文内容摘抄自Gorm 2022-8月份官方文档教程,如果Gorm框架后续有更新,还是以最新版本的官方文档为准
系列文章:
环境准备
先确保能够连接上指定的数据库并且将相关表创建好,这里用mysql作为演示:
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
const MYSQL_ADDR ="user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
type User struct
gorm.Model
Name string
Age int
Birthday time.Time
func main()
DB = openDB()
createTable()
func createTable()
DB.AutoMigrate(&User)
func openDB() *gorm.DB
db, err := gorm.Open(mysql.Open(MYSQL_ADDR), &gorm.Config)
if err != nil
panic("failed to connect database")
return db
创建
创建记录
func main()
DB = openDB()
user := UserName: "大忽悠", Age: 18, Birthday: time.Now()
result := DB.Create(&user) // 通过数据的指针来创建
fmt.Println("返回插入数据的主键: ", user.ID)
fmt.Println("返回 error: ", result.Error)
fmt.Println("返回插入记录的条数: ", result.RowsAffected)
用指定的字段创建记录
创建记录并更新给出的字段。
DB.Select("Name", "Age", "CreatedAt").Create(&user)
// INSERT INTO `users` (`name`,`age`,`created_at`) VALUES ("大忽悠", 18, "2022-08-04 11:05:21.775")
创建一个记录且一同忽略传递给略去的字段值。
DB.Omit("Name", "Age", "CreatedAt").Create(&user)
// INSERT INTO `users` (`birthday`,`updated_at`) VALUES ("2020-01-01 00:00:00.000", "2020-07-04 11:05:21.775")
批量插入
要有效地插入大量记录,请将一个 slice
传递给 Create
方法。 GORM
将生成单独一条SQL
语句来插入所有数据,并回填主键的值,钩子方法也会被调用。
var users = []UserName: "dhy1", Name: "dhy2", Name: "dhy3"
DB.Create(&users)
for _, user := range users
fmt.Printf("id=%d,name=%s,age=%d\\n", user.ID, user.Name, user.Age)
ERROR是因为Mysql5.7版本及以上版本的datetime值不能为’0000-00-00 00:00:00’,
解决方法: 修改mysql.int
在[mysqld]添加一项:sql_mode=NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,支持特殊的语法,这样就可以导入了,导入完毕后,移除兼容项即可。此方法简单,建议使用此方法。
使用 CreateInBatches
分批创建时,你可以指定每批的数量,例如:
var users = []UserName: "dhy1", Name: "dhy2", Name: "dhy3"
// 数量为 100
DB.CreateInBatches(users, 100)
Upsert 和 Create With Associations 也支持批量插入
注意 使用CreateBatchSize
选项初始化 GORM 时,所有的创建& 关联 INSERT
都将遵循该选项
func openDB() *gorm.DB
//针对全局设置
db, err := gorm.Open(mysql.Open(MYSQL_ADDR), &gorm.Config
CreateBatchSize: 1,
)
if err != nil
panic("failed to connect database")
return db
var users = []UserName: "dhy1", Name: "dhy2", Name: "dhy3"
//针对某次会话设置
DB.Session(&gorm.SessionCreateBatchSize: 1).Create(users)
创建钩子
GORM 允许用户定义的钩子有 BeforeSave
, BeforeCreate
, AfterSave
, AfterCreate
创建记录时将调用这些钩子方法,请参考 Hooks 中关于生命周期的详细信息
钩子方法常与模板方法模式搭配使用,通常暴露给用户自定义相关组件,以此提高框架整体可扩展性
func (u *User) BeforeCreate(tx *gorm.DB) (err error)
u.UUID = uuid.New()
if u.Role == "admin"
return errors.New("invalid role")
return
如果您想跳过 钩子
方法,您可以使用 SkipHooks
会话模式,例如:
//都是针对单词会话进行设置的
DB.Session(&gorm.SessionSkipHooks: true).Create(&user)
DB.Session(&gorm.SessionSkipHooks: true).Create(&users)
DB.Session(&gorm.SessionSkipHooks: true).CreateInBatches(users, 100)
根据 Map 创建
GORM 支持根据 map[string]interface
和 []map[string]interface
创建记录,例如:
DB.Model(&User).Create(map[string]interface
"Name": "DHY", "Age": 18,
)
// batch insert from `[]map[string]interface`
DB.Model(&User).Create([]map[string]interface
"Name": "dhy1", "Age": 18,
"Name": "dhy2", "Age": 20,
)
注意: 根据 map 创建记录时,association 不会被调用,且主键也不会自动填充
使用 SQL 表达式、Context Valuer 创建记录
GORM 允许使用 SQL 表达式插入数据,有两种方法实现这个目标。根据 map[string]interface
或 自定义数据类型 创建,例如:
// 通过 map 创建记录
DB.Model(User).Create(map[string]interface
"Name": clause.ExprSQL: "UPPER(?)", Vars: []interface"dhy",
"age": 18,
)
对应创建的sql语句为:
INSERT INTO `users` (`name`,`age`) VALUES (UPPER('dhy'),18)
通过自定义类型创建记录:
// 通过自定义类型创建记录
type Location struct
X, Y int
// Scan 方法实现了 sql.Scanner 接口
func (loc *Location) Scan(v interface) error
// Scan a value into struct from database driver
func (loc Location) GormDataType() string
return "geometry"
func (loc Location) GormValue(ctx context.Context, db *gorm.DB) clause.Expr
return clause.Expr
SQL: "ST_PointFromText(?)",
Vars: []interfacefmt.Sprintf("POINT(%d %d)", loc.X, loc.Y),
type User struct
Name string
Location Location
db.Create(&User
Name: "jinzhu",
Location: LocationX: 100, Y: 100,
)
// INSERT INTO `users` (`name`,`location`) VALUES ("jinzhu",ST_PointFromText("POINT(100 100)"))
高级选项
关联创建
创建关联数据时,如果关联值是非零值,这些关联会被 upsert,且它们的 Hook 方法也会被调用
upsert: 存在时更新,不存在时插入
type CreditCard struct
gorm.Model
Number string
UserID uint
type User struct
gorm.Model
Name string
CreditCard CreditCard
DB.Create(&User
Name: "jinzhu",
CreditCard: CreditCardNumber: "411111111111",
)
// INSERT INTO `users` ...
// INSERT INTO `credit_cards` ...
您也可以通过 Select、 Omit
跳过关联保存,例如:
db.Omit("CreditCard").Create(&user)
// 跳过所有关联
db.Omit(clause.Associations).Create(&user)
默认值
您可以通过标签 default
为字段定义默认值,如:
type User struct
ID int64
Name string `gorm:"default:galeone"`
Age int64 `gorm:"default:18"`
插入记录到数据库时,默认值 会被用于 填充值为 零值 的字段
注意: 对于声明了默认值的字段,像 0、‘’、false 等零值是不会保存到数据库。您需要使用指针类型或 Scanner/Valuer 来避免这个问题,例如:
type User struct
gorm.Model
Name string `gorm:"default:18"`
Age int `gorm:"default:100"`
Birthday time.Time `gorm:"default:2022-08-23 21:28:27.329"`
func main()
DB = openDB()
//我想保存相关数据类型的零值到数据库,但是由于默认值的存在,插入数据库的还是默认值
DB.Create(&User
Name: "",
Age: 0,
)
指针解决法:
type User struct
gorm.Model
Name *string `gorm:"default:18"`
Age *int `gorm:"default:100"`
Birthday time.Time `gorm:"default:2022-08-23 21:28:27.329"`
func main()
DB = openDB()
str := ""
age := 0
DB.Create(&User
Name: &str,
Age: &age,
)
Scanner/Valuer接口解决法:
type myString string
type User struct
gorm.Model
Name myString
Age int `gorm:"default:100"`
Birthday time.Time `gorm:"default:2022-08-23 21:28:27.329"`
//Scan 在从数据库读取记录到结构体时,当需要往某个字段注入值时,会先检查该字段是否实现了对应的Scan接口
//如果实现了,就利用该接口完成赋值
func (s *myString) Scan(src any) error
if src == nil
*s = ""
return nil
//... 我们需要在下面完成对当前字段的赋值
return nil
func (s myString) Value() (driver.Value, error)
if s == ""
//如果为空,就记录一下
fmt.Println("当前字段为空")
//注意: 如果返回的类型也实现了Value接口,会继续调用
//如果这里直接将s返回,会造成死循环,因为会不断去调用s的Value接口
return "hhhhh", nil
func main()
DB = openDB()
//在获取每个字段值时,会检查对应的字段有没有实现Value接口
//如果实现了,就获取Value接口的返回值,作为最终结果
DB.Create(&User
Name: "xpy",
Age: 0,
)
Gorm操作对象属性前,会先去寻找Scan和Value方法,如果有则调用,这一点类似Java中操作对象属性通常使用Getter和Setter方法一般。
default:(-)
标签可以让我们在字段为零值时,忽略该字段的插入。
type User struct
gorm.Model
Name myString
Age int `gorm:"default:(-)"`
Birthday time.Time `gorm:"default:2022-08-23 21:28:27.329"`
func main()
DB = openDB()
DB.Create(&User
Name: "xpy",
Age: 0,
)
- Age为0时,生成的insert语句忽略了该字段的插入
- Age不为0时,insert语句才会添加对应字段的插入
以上是关于Gorm框架学习---CRUD接口之创建的主要内容,如果未能解决你的问题,请参考以下文章
kratos学习从零使用kratos创建一个CRUD的demo,是gorm做数据库操作,经过几天研究,调试代码开源放到github上,还是非常方便的。服务也实现了CRUD的http接口。
kratos学习从零使用kratos创建一个CRUD的demo,是gorm做数据库操作,经过几天研究,调试代码开源放到github上,还是非常方便的。服务也实现了CRUD的http接口。