这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天
Gorm的使用
1. 连接数据库
import (
"gorm.io/driver/mysql" //gorm的mysql驱动
"gorm.io/gorm"
)
dsn := "root:123456@tcp(127.0.0.1:3306)/test_gorm?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic("Failed to connect to mysql!")
}
Gorm目前支持MySQL、SQLServer、PostgreSQL、SQLite,Gorm通过驱动来连接数据库
mysql.Open(dsn)
什么是dsn: github.com/go-sql-driv…
2. 定义gorm model
用一个结构体代表数据库的一张表,结构体的每个字段对应表的一个字段。
Gorm的约定(默认)
- 使用名为ID的键作为主键
- 使用结构体名的蛇形复数作为表名(例如 table_names)
- 字段名的蛇形作为列名
- 使用CreatedAt、UpdatedAt字段作为创建时间、更新时间
type Product struct {
Code string
Price uint
}
func (p Product) TableName() string { //表名
return "product"
}
3. Gorm 创建数据
使用res := db.Create(data)向数据库的表中一条或多条数据,然后可以用res.Error获取插入数据发送的错误
//插入一条数据
p := &Product{
Code: "D42",
Price: 100,
}
res := db.Create(p)
fmt.Println(res.Error)
//插入多条数据
products := []*Product{{Code: "D51"}, {Code: "D52"}}
res = db.Create(products)
fmt.Println(res.Error)
4. Gorm查询数据
查询单个记录
Grom提供了First、Take、Last方法,用于从数据库中检索单个对象。
First按主键升序获取第一条记录
相当于SELECT * From users ORDER BY id LIMIT 1
Last按主键降序获取第一条记录
相当于SELECT * FROM users ORDED BY id DESC LIMIT 1
Take获取一条记录,没有指定顺序
相当于SELECT * FROM users LIMIT 1
//获取第一条记录,按主键升序
p := &Product{}
db.First(p)
fmt.Println(p)
//获取第一条记录,按主键降序
db.Last(p)
fmt.Println(p)
//获取一条记录,无指定顺序
db.Take(p)
fmt.Println(p)
查询多个记录
使用result := db.Find(&product)方法可获取全部记录。
result.RowsAffected为查找到的记录的条数,
result.Error为返回的错误信息
可使用db.Where()方法带条件查询
如db.Where("name = ?", "jinzhu").First(&users)
db.Where("name <> ?", "jinzhu").First(&users)
也可以使用结构体或Map作为查询条件。使用结构体作为查询条件时只会查询非零字段。
可以通过指定主键来检索对象,如db.First(&user, 10),db.Find(&user, []int{1, 2, 3}),但只支持整型数值,因为string可能导致SQL注入。
注意
-
First查询不到数据会反回ErrRecordNotFond
-
Find查询不到数据不会返回错误
-
使用结构体作为查询条件会忽略零值,使用map不会
5. Gorm更新数据
//条件更新单个列
db.Model(&User{ID:111}).Where("age > ?", 18).Update("name", "Hello")
//更新多个列 使用struct 只更新非零值,map更新全部字段
db.Model(&User{ID:111}).Updates(map[string]interface{}{"name":"hello", "age":18, "actived":false})
//更新选定字段
db.Model(&User{ID:111}).Select("name").Updates(map[string]interface{}{"name":"hello", "age":18, "actived":false})
//SQL表达式更新
db.Model(&User{ID:111}).Update("age", gorm.Expr("age * ? + ?", 2, 100))
- 至少要有一个限定条件,如果没用使用Where等方法给出条件,Model方法中至少要有一个限定条件。
- 使用结构体更新时,只会更新非零值。要更新零值可以使用map更新或用Select选择字段更新
6. Gorm删除数据
有物理删除和软删除有种删除方式,物理删除真正把数据从表中删去,而软删除只会把DeletaAt字段置为当前时间,标志该条记录已被删除。
物理删除
db.Delete(&User{}, 10) //删除主键不10的一条记录
db.Where().Delete() //根Where的条件删除数据
软删除
提供gorm.DeletaAt字段,就拥有了软删除能力。
调用Delete方法删除时,记录不会从数据库中真正删除
只会将DeltetaAt置为当前时间
使用Unscoped可以查询到被软删的数据
type User struct {
ID int64,
Name stirng,
Age int64,
Deletad gorm.DeletaAt
}
7. Gorm事务
Gorm提供了Begin、Commit、Rollback、方法用于使用事务
tx := db.Begin()
if err := tx.Create(); err != nil {
//遇到错误时回滚事务
tx.Rollback()
return
}
if err := tx.Create(); err != nil {
tx.Rollback()
return
}
//提交事务
tx.Commit()
Gorm提供了Transcation方法用于自动提交事务,避免漏写Commit或Rollback
if err := db.Transcation(func(tx *gorm.DB) error {
//事务
return nil
}); err != nil {
return
}
在执行事务操作时,应使用tx而不是db
8. Gorm Hock
Gorm提供了CURD的Hook能力
Hook是在创建、查询、更新、删除等操作之前或之后自动调用的函数
如果Hook返回错误,Gorm将停止后续操作并回流事务
//在Create前自动执行
func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
}
//在Create后自动执行
func (u *User) AfterCreate(tx *gorm.DB) (err error) {
}
9. Gorm性能提高
对于写操作(创建,更新,删除),为了确保数据的完整性,Gorm会将它们封装在事务中运行,这会降低性能。可以使用SkipDefaultTranscation关闭默认事务。
使用PrepareStmt缓存预编译语句可以提高后续调用速度。
gorm.Config {
SkipDefaultTranscation: true, //关闭默认事务
PrepareStmt: true //缓存预编译语句
}