Gorm的使用 | 青训营笔记

142 阅读4分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 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	//缓存预编译语句
}