引言
GORM 是 Go 语言中一款优秀的 ORM(Object-Relational Mapping)库,它可以让我们用 Go 对象的方式来操作数据库,而不需要直接编写 SQL 语句。GORM 支持多种数据库,如 MySQL、PostgreSQL、SQLite、SQL Server 等,提供了丰富的功能和灵活的配置,让我们可以轻松地实现数据库的增删改查操作。
本文将介绍 GORM 的基本使用方法,包括如何安装和配置 GORM,如何定义和迁移数据模型,以及如何进行 CRUD(Create, Read, Update, Delete)操作。本文的示例代码使用 MySQL 数据库,但也适用于其他数据库。
安装和配置 GORM
要使用 GORM,首先需要安装 GORM 库和相应的数据库驱动。我们可以使用 go get 命令来安装:
// 安装 GORM 库
go get -u gorm.io/gorm
// 安装 MySQL 驱动
go get -u gorm.io/driver/mysql
安装完成后,我们就可以在代码中导入 GORM 库和驱动:
import (
"gorm.io/gorm"
"gorm.io/driver/mysql"
)
定义和迁移数据模型
在 GORM 中,我们可以使用结构体来定义数据模型,每个结构体对应一张数据表,每个字段对应一列数据。GORM 提供了一些标签(Tag)来控制结构体和数据表之间的映射关系,例如:
// 定义一个 User 结构体,对应 users 表
type User struct {
ID uint `gorm:"primaryKey"` // 主键
Name string `gorm:"size:64"` // 姓名,长度为 64
Age int `gorm:"default:18"` // 年龄,默认为 18
Email string `gorm:"unique"` // 邮箱,唯一约束
CreatedAt time.Time // 创建时间
UpdatedAt time.Time // 更新时间
}
如果没有指定标签,GORM 会根据一些默认规则来映射结构体和数据表。例如:
- 结构体名对应表名的单数形式(如果表名是复数形式,需要设置
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{NamingStrategy: schema.NamingStrategy{SingularTable: true}})来禁用复数表名) - 字段名对应列名的蛇形命名法(Snake Case),即大写字母转为小写并以下划线分隔
- 如果字段类型是 time.Time 或 *time.Time,则会自动添加 NOT NULL DEFAULT CURRENT_TIMESTAMP 和 ON UPDATE CURRENT_TIMESTAMP 约束
有了结构体定义后,我们就可以使用 GORM 的 AutoMigrate 方法来自动创建或更新数据表了。AutoMigrate 方法会根据结构体的定义来创建或修改数据表,并保留原有的数据。如果数据表已经存在,AutoMigrate 方法会添加缺少的列或索引,但不会删除或修改已有的列或索引。例如:
// 根据 User 结构体自动创建或更新 users 表
err := db.AutoMigrate(&User{})
if err != nil {
panic("failed to migrate database")
}
如果我们想要删除数据表,我们可以使用 Migrator 方法来获取一个迁移器对象,然后调用 DropTable 方法来删除指定的表。例如:
// 删除 users 表
err := db.Migrator().DropTable(&User{})
if err != nil {
panic("failed to drop table")
}
进行 CRUD 操作
有了数据库连接和数据模型后,我们就可以使用 GORM 来进行 CRUD(Create, Read, Update, Delete)操作了。GORM 提供了一系列的方法来实现这些操作,我们可以通过链式调用的方式来组合不同的方法,以实现复杂的查询逻辑。下面我们分别介绍这些操作的基本用法。
Create
要向数据库中插入一条记录,我们可以使用 Create 方法,该方法接受一个结构体或切片作为参数,返回一个结果对象,该对象包含了插入操作的相关信息,例如影响的行数、错误信息等。例如:
// 创建一个 User 对象
user := User{Name: "Alice", Age: 20, Email: "alice@example.com"}
// 向 users 表中插入一条记录
result := db.Create(&user)
// 获取插入操作的结果
fmt.Println(result.RowsAffected) // 影响的行数
fmt.Println(result.Error) // 错误信息
fmt.Println(user.ID) // 自增主键的值
如果要向数据库中插入多条记录,我们可以使用切片作为参数,例如:
// 创建一个 User 切片
users := []User{
{Name: "Bob", Age: 21, Email: "bob@example.com"},
{Name: "Carol", Age: 22, Email: "carol@example.com"},
}
// 向 users 表中插入多条记录
result := db.Create(&users)
// 获取插入操作的结果
fmt.Println(result.RowsAffected) // 影响的行数
fmt.Println(result.Error) // 错误信息
fmt.Println(users[0].ID) // 第一条记录的主键值
fmt.Println(users[1].ID) // 第二条记录的主键值
Read
要从数据库中查询一条或多条记录,我们可以使用 First、Take、Last、Find 等方法,这些方法都接受一个结构体或切片作为参数,并将查询结果赋值给该参数。如果查询成功,这些方法会返回一个结果对象,该对象包含了查询操作的相关信息,例如影响的行数、错误信息等。如果查询失败,这些方法会返回一个 ErrRecordNotFound 错误。例如:
// 查询 users 表中第一条记录,并赋值给 user 对象
var user User
result := db.First(&user)
// 获取查询操作的结果
fmt.Println(result.RowsAffected) // 影响的行数
fmt.Println(result.Error) // 错误信息
fmt.Println(user) // user 对象的值
// 查询 users 表中所有记录,并赋值给 users 切片
var users []User
result = db.Find(&users)
// 获取查询操作的结果
fmt.Println(result.RowsAffected) // 影响的行数
fmt.Println(result.Error) // 错误信息
fmt.Println(users) // users 切片的值
如果要对查询结果进行筛选或排序,我们可以使用 Where、Order、Limit 等方法来指定查询条件或选项。这些方法都会返回一个 *gorm.DB 类型的对象,该对象包含了查询语句的相关信息,我们可以继续调用其他方法来执行查询操作。例如:
// 查询 users 表中年龄大于 18 的记录,并按照年龄升序排序,只取前两条记录
var users []User
result := db.Where("age > ?", 18).Order("age asc").Limit(2).Find(&users)
// 获取查询操作的结果
fmt.Println(result.RowsAffected) // 影响的行数
fmt.Println(result.Error) // 错误信息
fmt.Println(users) // users 切片的值
这些方法的参数可以是字符串、结构体、切片、字典或函数,具体的用法可以参考 GORM 的文档。我们也可以使用 Raw 方法来直接编写 SQL 语句来执行查询操作,例如:
// 使用 SQL 语句查询 users 表中年龄最大的记录,并赋值给 user 对象
var user User
result := db.Raw("SELECT * FROM users ORDER BY age DESC LIMIT 1").Scan(&user)
// 获取查询操作的结果
fmt.Println(result.RowsAffected) // 影响的行数
fmt.Println(result.Error) // 错误信息
fmt.Println(user) // user 对象的值
Update
要更新数据库中的一条或多条记录,我们可以使用 Update、Updates、Save 等方法,这些方法都接受一个结构体或字典作为参数,并返回一个结果对象,该对象包含了更新操作的相关信息,例如影响的行数、错误信息等。例如:
// 更新 users 表中第一条记录的姓名为 "Alice"
result := db.Model(&User{}).Where("id = ?", 1).Update("name", "Alice")
fmt.Println(result.RowsAffected) // 影响的行数
fmt.Println(result.Error) // 错误信息
result = db.Model(&User{}).Update("age", gorm.Expr("age + ?", 1))
// 获取更新操作的结果
fmt.Println(result.RowsAffected) // 影响的行数
fmt.Println(result.Error) // 错误信息
// 使用 user 对象更新 users 表中对应记录的所有字段(除了主键和创建时间)
user := User{ID: 1, Name: "Alice", Age: 20, Email: "alice@example.com"}
result = db.Save(&user)
fmt.Println(result.RowsAffected) // 影响的行数
fmt.Println(result.Error) // 错误信息
如果要更新多个字段,我们可以使用字典作为参数,例如:
// 更新 users 表中第一条记录的姓名和年龄为 "Alice" 和 20
result := db.Model(&User{}).Where("id = ?", 1).Updates(map[string]interface{}{"name": "Alice", "age": 20})
// 获取更新操作的结果
fmt.Println(result.RowsAffected) // 影响的行数
fmt.Println(result.Error) // 错误信息
Delete
要删除数据库中的一条或多条记录,我们可以使用 Delete 方法,该方法接受一个结构体或切片作为参数,并返回一个结果对象,该对象包含了删除操作的相关信息,例如影响的行数、错误信息等。例如:
// 删除 users 表中第一条记录
result := db.Delete(&User{}, 1)
// 获取删除操作的结果
fmt.Println(result.RowsAffected)
fmt.Println(result.Error)
// 删除 users 表中所有记录
result = db.Delete(&User{})
// 获取删除操作的结果
fmt.Println(result.RowsAffected)
fmt.Println(result.Error)
// 删除 users 切片中对应的记录(根据主键)
users := []User{
{ID: 2},
{ID: 3},
}
result = db.Delete(&users)
// 获取删除操作的结果
fmt.Println(result.RowsAffected)
fmt.Println(result.Error)
如果要对删除结果进行筛选,我们可以使用 Where 方法来指定删除条件,例如:
// 删除 users 表中年龄小于 18 的记录
result := db.Where("age < ?", 18).Delete(&User{})
// 获取删除操作的结果
fmt.Println(result.RowsAffected) // 影响的行数
fmt.Println(result.Error) // 错误信息
总结
本文介绍了 GORM 的基本使用方法,包括如何安装和配置 GORM,如何定义和迁移数据模型,以及如何进行 CRUD 操作。GORM 是一款功能强大、易用的 ORM 库,它可以让我们用 Go 对象的方式来操作数据库,而不需要直接编写 SQL 语句。