GORM框架入门|青训营

269 阅读4分钟

这是青训营笔记的第一篇文章。

使用GORM连接MySQL数据库并实现CRUD

准备工作

安装GORM

go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite

创建一个用于测试的test库

命令行,MySQL workbench,datagrip任君选择

基本要素

数据库连接

首先根据数据库配置,获取对应的DSN,具体格式为 {用户名}:{密码}@tcp({服务器地址}:{端口号})/{数据库名称}?{配置信息,如字符集指定等}

  import (
  "gorm.io/driver/mysql"//此处务必使用
        //gorm提供的MySQL驱动,使用官方驱动会出错
  "gorm.io/gorm"
)

func main() {
  dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
  db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
}

更多进阶内容请移步官方文档gorm.io/zh_CN/docs/…

定义数据模型

模型是标准的 struct,由 Go 的基本数据类型、实现了 Scanner 和 Valuer 接口的自定义类型及其指针或别名组成 此教程中,我们简化官方文档的实例代码,定义User作为数据模型

type User struct {
ID           uint
Name         string
Email        *string
Age          uint8
Birthday     *time.Time
CreatedAt    time.Time
UpdatedAt    time.Time
}
  ```
使用语句
```go
db.AutoMigrate(&User{})
  // 可以通过Set设置附加参数,下面设置表的存储引擎为InnoDB
db.Set("gorm:table_options", "ENGINE=InnoDB").AutoMigrate(&User{})

GORM将会根据User声明自动生成对应的表Users

进行数据库操作

基本范式:按照MySQL语句的执行顺序调用方法 GORM本质上是一个SQLY语句生成软件,通过迁移SQL逻辑,我们可以快速上手GORM

创建

创建单项记录
user := User{Name: "Xiaolin", Age: 18, Birthday: time.Now()}

result := db.Create(&user) // 通过数据的指针来创建
//使用result接收数据库返回,将记录打印到标准输出或者日志
user.ID             // 返回插入数据的主键
result.Error        // 返回 error
result.RowsAffected // 返回插入记录的条数
创建多项记录
users := []*User{
    User{Name: "Xiaolin", Age: 18, Birthday: time.Now()},
    User{Name: "Jackson", Age: 19, Birthday: time.Now()},
}

result := db.Create(users) // pass a slice to insert multiple row

result.Error        // returns error
result.RowsAffected // returns inserted records count
用指定的字段创建记录
db.Select().Create()
db.Omit().Create()

查询

最简单的查询

假设我想要查询上述所创建表中的单个记录,GORM 提供了 First、Take、Last 方法,在没有找到记录时,它会返回 ErrRecordNotFound 错误。

// 获取第一条记录(主键升序)
db.First(&user)
// SELECT * FROM users ORDER BY id LIMIT 1;
 
result := db.First(&user)
result.RowsAffected // 返回找到的记录数
result.Error        // returns error or nil

// 检查 ErrRecordNotFound 错误
errors.Is(result.Error, gorm.ErrRecordNotFound)

如果要避免ErrRecordNotFound 错误,可以使用Find,如:

db.Limit(1).Find(&user)

值得注意的是,对单个对象使用Find而不带limit,db.Find(&user)将会查询整个表并且只返回第一个对象,这是性能不高并且不确定的。

当目标对象有一个主键值时,将使用主键构建查询条件,例如:

var result User
db.Model(User{ID: 10}).First(&result)
// SELECT * FROM users WHERE id = 10;

使用Find方法,可以查询所有符合条件的对象

// Get all records
result := db.Find(&users)
// SELECT * FROM users;

result.RowsAffected // returns found records count, equals `len(users)`
result.Error        // returns error
带条件查询

GROM支持多种条件输入方式:

  1. String条件
  2. Struct&Map条件
  3. SQL注入
String条件

一言以蔽之,就是以? 作为占位符,通过格式化字符串的输入方式来编写条件,例如:

// Get first matched record
db.Where("name = ?", "jinzhu").First(&user)
// SELECT * FROM users WHERE name = 'jinzhu' ORDER BY id LIMIT 1;

 
Struct & Map 条件

Struct & Map 本身就是一种对应关系的抽象数据结构,这就更好理解了

// Struct
db.Where(&User{Name: "jinzhu", Age: 20}).First(&user)
// SELECT * FROM users WHERE name = "jinzhu" AND age = 20 ORDER BY id LIMIT 1;
 

更新

保存所有字段

Save 会保存所有的字段,即使字段是零值。 Save 方法是一个组合逻辑函数。如果要保存的值不包含主键,他会执行Create,否则执行Update。

db.First(&user)

user.Name = "jinzhu 2"
user.Age = 100
db.Save(&user)

db.Save(&User{Name: "jinzhu", Age: 100})
// INSERT INTO `users` (`name`,`age`,`birthday`,`update_at`) VALUES ("jinzhu",100,"0000-00-00 00:00:00","0000-00-00 00:00:00")

 
更新单列

首先输入约束条件,然后执行Update操作

// Update with conditions
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;
 
更新多列

在单列语句的基础上,将Update中的语句替换为Struct & Map。 需要注意的是,使用struct更新,只会更新非0的数据。

 
db.Model(&user).Updates(User{Name: "hello", Age: 18, Active: false})
// UPDATE users SET name='hello', age=18, updated_at = '2013-11-17 21:34:10' WHERE id = 111;


db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// UPDATE users SET name='hello', age=18, active=false, updated_at='2013-11-17 21:34:10' WHERE id=111;

更新选定字段

使用Select或者Omit方法

// User's ID is `111`:
db.Model(&user).Select("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})

删除

删除一条记录时,删除对象需要指定主键,否则会触发 批量删除,例如:

// Email 的 ID 是 `10`
db.Delete(&email)
// DELETE from emails where id = 10;

// 带额外条件的删除
db.Where("name = ?", "jinzhu").Delete(&email)
// DELETE from emails where id = 10 AND name = "jinzhu";

总结

在使用GORM框架时,只需要遵循SQL语句的逻辑,调用对应的方法,便可以轻易实现go程序到数据库的连接。