GORM(Go的ORM库)入门教程
GORM是一个用于Go语言的对象关系映射(ORM)库,它可以让我们用Go语言的结构体和方法来操作数据库中的表和记录,而不需要直接编写SQL语句。GORM支持多种数据库驱动,包括MySQL、PostgreSQL、SQLite、SQL Server等。GORM提供了丰富的功能和灵活的API,让我们可以轻松地实现数据库的增、删、改、查等操作。
在本教程中,我们将学习如何使用GORM连接数据库,并实现增、删、改、查四种操作。我们将以MySQL数据库为例,但你也可以根据自己的需要选择其他数据库驱动。我们假设你已经安装了Go语言环境和MySQL数据库,并且在MySQL中创建了一个名为gorm_test的数据库。
连接数据库
要使用GORM连接数据库,我们首先需要导入gorm.io/gorm和gorm.io/driver/mysql两个包,分别提供了GORM的核心功能和MySQL驱动。然后,我们可以使用gorm.Open()函数来打开一个数据库连接,它接受两个参数:一个是数据库驱动,一个是数据源名称(DSN)。DSN是一个字符串,用于指定数据库的地址、端口、用户名、密码、名称等信息。我们可以使用fmt.Sprintf()函数来动态生成DSN,例如:
// 导入包
import (
"fmt"
"gorm.io/gorm"
"gorm.io/driver/mysql"
)
// 定义数据库相关常量
const (
DB_HOST = "localhost"
DB_PORT = 3306
DB_USER = "root"
DB_PASS = "123456"
DB_NAME = "gorm_test"
)
// 生成DSN
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", DB_USER, DB_PASS, DB_HOST, DB_PORT, DB_NAME)
// 打开数据库连接
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
如果连接成功,gorm.Open()函数会返回一个*gorm.DB类型的值,它代表了一个数据库连接会话,我们可以通过它来执行后续的操作。如果连接失败,它会返回一个错误值,我们可以通过panic()函数来抛出异常并终止程序。
定义模型
在GORM中,我们可以使用Go语言的结构体来定义模型(Model),它代表了数据库中的一张表。每个结构体字段对应了表中的一列,我们可以通过标签(Tag)来指定字段的名称、类型、约束等属性。例如,我们可以定义一个名为User的模型,它对应了数据库中的users表:
// 定义User模型
type User struct {
ID uint `gorm:"primaryKey"` // 主键
Name string `gorm:"size:64"` // 姓名,最大长度64
Email string `gorm:"unique"` // 邮箱,唯一约束
Password string `gorm:"not null"` // 密码,非空约束
CreatedAt time.Time // 创建时间
UpdatedAt time.Time // 更新时间
}
在上面的代码中,我们使用了gorm:"..."标签来指定GORM相关的属性,例如:
primaryKey表示该字段是主键,GORM会自动为其生成自增的值。size:64表示该字段的最大长度是64个字符。unique表示该字段具有唯一性约束,不能有重复的值。not null表示该字段具有非空约束,不能为NULL。
我们也可以使用其他标签来指定非GORM相关的属性,例如:
json:"..."表示该字段在JSON格式中的名称,用于序列化和反序列化。validate:"..."表示该字段的验证规则,用于数据校验。
创建表
在定义了模型之后,我们可以使用GORM的AutoMigrate()方法来自动创建或更新数据库中的表。它接受一个或多个模型类型作为参数,然后根据模型的定义来生成对应的SQL语句,并执行它们。例如,我们可以使用以下代码来创建users表:
// 创建users表
err = db.AutoMigrate(&User{})
if err != nil {
panic("failed to create table")
}
如果表不存在,AutoMigrate()方法会创建一个新的表;如果表已经存在,它会根据模型的变化来更新表结构,但不会删除已有的列和数据。如果创建或更新失败,它会返回一个错误值,我们可以通过panic()函数来抛出异常并终止程序。
增加记录
在创建了表之后,我们可以使用GORM的Create()方法来向表中插入一条或多条记录。它接受一个或多个模型实例作为参数,然后根据模型的定义来生成对应的SQL语句,并执行它们。例如,我们可以使用以下代码来向users表中插入一条记录:
// 创建一个User实例
user := User{
Name: "Alice",
Email: "alice@example.com",
Password: "123456",
}
// 向users表中插入一条记录
result := db.Create(&user)
if result.Error != nil {
panic("failed to insert record")
}
如果插入成功,Create()方法会返回一个*gorm.DB类型的值,它包含了执行结果的相关信息,例如:
RowsAffected表示影响的行数,即插入的记录数。Error表示执行过程中发生的错误,如果没有错误,则为nil。PrimaryValue表示插入记录的主键值,如果有多个主键,则为第一个主键值。
如果插入失败,Create()方法会返回一个错误值,我们可以通过panic()函数来抛出异常并终止程序。
查询记录
在向表中插入了记录之后,我们可以使用GORM的各种查询方法来从表中查询一条或多条记录。这些查询方法都是基于*gorm.DB类型的值进行链式调用的,每个方法都会返回一个新的*gorm.DB类型的值,它包含了查询条件和结果。我们可以通过以下几种方式来指定查询条件:
- 使用
Where()方法来指定过滤条件,它接受一个字符串、一个结构体、一个字典或一个切片作为参数,然后根据参数的类型和内容来生成对应的SQL语句,并执行它们。例如:
// 查询姓名为Alice的用户
db.Where("name = ?", "Alice").Find(&users)
// 查询邮箱以.com结尾的用户
db.Where("email LIKE ?", "%.com").Find(&users)
// 查询ID在1到10之间的用户
db.Where("id BETWEEN ? AND ?", 1, 10).Find(&users)
// 查询ID为1或2或3的用户
db.Where("id IN ?", []int{1, 2, 3}).Find(&users)
// 查询创建时间在2023年1月1日之后的用户
db.Where("created_at > ?", "2023-01-01").Find(&users)
// 使用结构体作为参数,只会查询非零值字段
db.Where(&User{Name: "Alice", Email: "alice@example.com"}).Find(&usersid + 1")} }).Find(&results)
在指定了查询条件之后,我们可以使用以下几种方法来获取查询结果:
- 使用
Find()方法来查询多条记录,它接受一个切片的指针作为参数,然后将查询结果追加到该切片中。例如:
// 定义一个User切片
var users []User
// 查询所有用户,并将结果追加到users切片中
db.Find(&users)
// 查询姓名为Alice的用户,并将结果追加到users切片中
db.Where("name = ?", "Alice").Find(&users)
- 使用
First()方法来查询第一条记录,它接受一个结构体的指针作为参数,然后将查询结果赋值给该结构体。如果没有找到匹配的记录,它会返回一个ErrRecordNotFound错误。例如:
// 定义一个User结构体
var user User
// 查询第一条用户,并将结果赋值给user结构体
result := db.First(&user)
if result.Error != nil {
// 处理错误
}
// 查询ID为1的用户,并将结果赋值给user结构体
result = db.Where("id = ?", 1).First(&user)
if result.Error != nil {
// 处理错误
}
- 使用
Last()方法来查询最后一条记录,它接受一个结构体的指针作为参数,然后将查询结果赋值给该结构体。如果没有找到匹配的记录,它会返回一个ErrRecordNotFound错误。例如:
// 定义一个User结构体
var user User
// 查询最后一条用户,并将结果赋值给user结构体
result := db.Last(&user)
if result.Error != nil {
// 处理错误
}
// 查询ID为10的用户,并将结果赋值给user结构体
result = db.Where("id = ?", 10).Last(&user)
if result.Error != nil {
// 处理错误
}
- 使用
Take()方法来查询一条记录,它接受一个结构体的指针作为参数,然后将查询结果赋值给该结构体。如果没有找到匹配的记录,它会返回一个ErrRecordNotFound错误。例如:
// 定义一个User结构体
var user User
// 查询一条用户,并将结果赋值给user结构体
result := db.Take(&user)
if result.Error != nil {
// 处理错误
}
// 查询姓名为Bob的用户,并将结果赋值给user结构体
result = db.Where("name = ?", "Bob").Take(&user)
if result.Error != nil {
// 处理错误
}
- 使用
Count()方法来统计记录数,它接受一个整数的指针作为参数,然后将查询结果赋值给该整数。例如:
// 定义一个整数变量
var count int64
// 统计所有用户的数量,并将结果赋值给count变量
db.Model(&User{}).Count(&count)
// 统计姓名为Alice的用户的数量,并将结果赋值给count变量
db.Model(&User{}).Where("name = ?", "Alice").Count(&count)
- 使用
Pluck()方法来提取单个字段的值,它接受一个字符串和一个切片的指针作为参数,然后将查询结果追加到该切片中。例如:
// 定义一个字符串切片
var names []string
// 提取所有用户的姓名,并将结果追加到names切片中
db.Model(&User{}).Pluck("name", &names)
// 提取ID大于5的用户的姓名,并将结果追加到names切片中
db.Model(&User{}).Where("id > ?", 5).Pluck("name", &names)
- 使用
Scan()方法来扫描记录到任意类型的变量,它接受任意类型的变量作为参数,然后根据字段名或者标签来匹配查询结果,并赋值给该变量。例如:
// 定义一个结构体,用于接收查询结果
type Result struct {
Name string `gorm:"column:name"` // 指定字段名
Count int `gorm:"column:count"`
}
// 定义一个Result切片
var results []Result
// 按照姓名分组,统计每个姓名的用户数量,并将结果扫描到results切片中
db.Model(&User{}).Select("name, count(*) as count").Group("name").Scan(&results)
修改记录
在从表中查询了记录之后,我们可以使用GORM的Update()方法来修改一条或多条记录。它接受一个字符串、一个结构体、一个字典或一个函数作为参数,然后根据参数的类型和内容来生成对应的SQL语句,并执行它们。例如:
// 查询ID为1的用户,并将其赋值给user变量
var user User
db.First(&user, 1)
// 修改用户的姓名为Bob,使用字符串作为参数,表示要修改的字段名
db.Model(&user).Update("name", "Bob")
// 修改用户的邮箱和密码,使用结构体作为参数,只会修改非零值字段
db.Model(&user).Update(User{Email: "bob@example.com", Password: "654321"})
// 修改用户的邮箱和密码,使用字典作为参数,可以指定字段名和值
db.Model(&user).Update(map[string]interface{}{"email": "bob@example.com", "password": "654321"})
// 修改用户的邮箱和密码,使用函数作为参数,可以用闭包来动态生成字段名和值
db.Model(&user).Update(func(db *gorm.DB) interface{} {
return map[string]interface{}{"email": "bob@example.com", "password": "654321"}
})
如果要修改多条记录,我们可以先指定查询条件,然后调用Update()方法。例如:
// 修改所有用户的密码为123456,使用字符串作为参数,表示要修改的字段名
db.Model(&User{}).Update("password", "123456")
// 修改所有用户的密码为123456,使用结构体作为参数,只会修改非零值字段
db.Model(&User{}).Update(User{Password: "123456"})
// 修改所有用户的密码为123456,使用字典作为参数,可以指定字段名和值
db.Model(&User{}).Update(map[string]interface{}{"password": "123456"})
// 修改所有用户的密码为123456,使用函数作为参数,可以用闭包来动态生成字段名和值
db.Model(&User{}).Update(func(db *gorm.DB) interface{} {
return map[string]interface{}{"password": "123456"}
})
如果要修改多个字段,我们可以使用Updates()方法来一次性修改。它接受一个结构体、一个字典或一个函数作为参数,然后根据参数的类型和内容来生成对应的SQL语句,并执行它们。例如,我们可以使用结构体作为参数来修改用户的姓名和密码,这只会修改非零值字段。
// 修改所有用户的姓名、邮箱和密码,使用结构体作为参数,只会修改非零值字段
db.Model(&User{}).Updates(User{Name: "Tom", Email: "tom@example.com", Password: "123456"})
// 修改所有用户的姓名、邮箱和密码,使用字典作为参数,可以指定字段名和值
db.Model(&User{}).Updates(map[string]interface{}{"name": "Tom", "email": "tom@example.com", "password": "123456"})
// 修改所有用户的姓名、邮箱和密码,使用函数作为参数,可以用闭包来动态生成字段名和值
db.Model(&User{}).Updates(func(db *gorm.DB) interface{} {
return map[string]interface{}{"name": "Tom", "email": "tom@example.com", "password": "123456"}
})
删除记录
在从表中查询了记录之后,我们可以使用GORM的Delete()方法来删除一条或多条记录。它接受一个结构体、一个切片或一个函数作为参数,然后根据参数的类型和内容来生成对应的SQL语句,并执行它们。例如:
// 查询ID为1的用户,并将其赋值给user变量
var user User
db.First(&user, 1)
// 删除用户,使用结构体作为参数,表示要删除的记录
db.Delete(&user)
// 删除用户,使用切片作为参数,表示要删除的记录
db.Delete([]User{{ID: 1}, {ID: 2}})
// 删除用户,使用函数作为参数,表示要删除的记录
db.Delete(func(db *gorm.DB) interface{} {
return []User{{ID: 1}, {ID: 2}}
})
如果要删除多条记录,我们可以先指定查询条件,然后调用Delete()方法。例如:
// 删除所有用户
db.Delete(&User{})
// 删除姓名为Alice的用户
db.Where("name = ?", "Alice").Delete(&User{})
// 删除ID大于5的用户
db.Where("id > ?", 5).Delete(&User{})
总结
在本教程中,我们学习了如何使用GORM(Go的ORM库)连接数据库,并实现增、删、改、查四种操作。我们了解了如何定义模型、创建表、增加记录、查询记录、修改记录和删除记录。我们还学习了如何使用各种方法来指定查询条件和结果,并使用标签来指定字段属性。通过GORM,我们可以用Go语言的结构体和方法来操作数据库中的表和记录,而不需要直接编写SQL语句。这样可以提高我们的开发效率和代码可读性。