Gorm 一个go开发中的常用ORM
安装使用步骤
使用 Gorm 的步骤如下:
- 安装 Gorm:可以使用 go get 命令安装 Gorm,如下所示:
go get -u gorm.io/gorm //安装GORM
go get -u gorm.io/driver/postgres //安装postgres驱动程序
查看是否安装成功及版本信息
看起来你的系统不是基于 Linux 或 macOS,而是基于 Windows。在 Windows 系统中,命令行工具和 Linux 或 macOS 系统中的略有不同。你可以使用以下命令来检查 Gorm 是否安装成功:
go list -m all | findstr "gorm.io/gorm"
如果安装成功,会输出 Gorm 的版本信息,例如:
gorm.io/gorm v1.21.11
如果没有输出任何信息,说明 Gorm 没有安装成功。
另外,你也可以在代码中使用以下语句来输出 Gorm 的版本信息:
fmt.Println("Gorm version:", gorm.Version)
这样就可以在程序运行时输出 Gorm 的版本信息了。
- 导入 Gorm 包:在 Go 代码中导入 Gorm 包,如下所示:
import (
"gorm.io/gorm"
"gorm.io/driver/postgres"
)
- 配置数据库连接:在代码中配置数据库连接,如下所示:
dsn := "host=123.57.166.115 user=postgres password=Nrec1234. dbname=postgres port=5432 sslmode=disable TimeZone=Asia/Shanghai"
//dsn := "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
//处理错误
panic(err)
}
其中,dsn 是数据库连接字符串,包括用户名、密码、主机地址、端口号、数据库名等信息。在这个例子中,我们使用 pgsql 数据库,dsn 中的参数表示使用 UTF-8 编码,开启时间解析,使用本地时间。
- 定义数据模型:在代码中定义数据模型,如下所示:
type User struct {
ID uint
Name string
Age int
}
在这个例子中,我们定义了一个 User 结构体,包括 ID、Name、Age 三个字段。
- 创建表格:在代码中使用 Gorm 自动创建表格,如下所示:
err := db.AutoMigrate(&User{})
if err != nil {
// 处理错误
}
这个例子中,我们使用 db.AutoMigrate() 方法自动创建 User 表格。
- 插入数据:在代码中使用 Gorm 插入数据,如下所示:
user := User{Name: "Tom", Age: 18}
result := db.Create(&user)
if result.Error != nil {
// 处理错误
}
这个例子中,我们创建了一个 User 对象,然后使用 db.Create() 方法将其插入到数据库中。
- 查询数据:在代码中使用 Gorm 查询数据,如下所示:
var users []User
result := db.Find(&users)
if result.Error != nil {
// 处理错误
}
这个例子中,我们使用 db.Find() 方法查询所有的 User 记录,并将结果存储在一个 User 数组中。
- 更新数据:在代码中使用 Gorm 更新数据,如下所示:
result := db.Model(&user).Update("Name", "Jerry")
if result.Error != nil {
// 处理错误
}
这个例子中,我们使用 db.Model() 方法指定要更新的数据模型,然后使用 Update() 方法更新 Name 字段的值。
- 删除数据:在代码中使用 Gorm 删除数据,如下所示:
result := db.Delete(&user)
if result.Error != nil {
// 处理错误
}
这个例子中,我们使用 db.Delete() 方法删除指定的 User 记录。
以上就是使用 Gorm 的基本步骤,具体使用时可以根据实际情况进行调整。
完整代码
package main
import (
"github.com/gin-gonic/gin"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
type User struct {
ID uint
Name string
Age int
}
func main() {
dsn := "host=123.57.166.115 user=postgres password=Nrec1234. dbname=postgres port=5432 sslmode=disable TimeZone=Asia/Shanghai"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
//panic(err)
}
err3 := db.AutoMigrate(&User{})
if err3 != nil {
// 处理错误
}
user := User{Name: "Tom", Age: 18}
result := db.Create(&user)
if result.Error != nil {
// 处理错误
}
var users []User
result2 := db.Find(&users)
if result2.Error != nil {
// 处理错误
}
result3 := db.Model(&user).Update("Name", "Jerry")
if result3.Error != nil {
// 处理错误
}
result4 := db.Delete(&user)
if result4.Error != nil {
// 处理错误
}
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello, World!",
})
})
r.Run(":8083")
}
gorm.Open
gorm.Open() 函数的定义如下:
func Open(dialect string, dsn string, config *Config) (*DB, error)
其中,参数含义如下:
dialect:数据库方言,例如mysql、postgres等。dsn:数据源名称,包括连接数据库的用户名、密码、主机名、端口号、数据库名称等信息。config:GORM 配置,包括连接池、日志等配置信息。这个参数需要传递一个*Config类型的指针。
函数返回值为一个 *DB 类型的指针和一个 error 类型的值。如果打开数据库连接成功,返回一个指向 *DB 类型的指针;否则返回一个非空的 error 类型的值,表示打开数据库连接失败的原因。
//&gorm.Config{}表示创建一个gorm.Config结构体,并将地址传入。因为gorm.Open的参数二需要一个指针
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
这行代码使用 GORM 库来连接到 PostgreSQL 数据库。具体来说,它执行以下操作:
- 使用
postgres.Open(dsn)函数创建一个 PostgreSQL 数据库驱动程序。 - 使用
gorm.Config{}配置选项创建一个 GORM 数据库连接。 - 使用
gorm.Open()函数将数据库驱动程序和 GORM 连接选项传递给 GORM 库,以打开与数据库的连接。 - 如果成功建立连接,则将连接存储在
db变量中,否则将错误存储在err变量中。
需要注意的是,dsn 是连接字符串,它包含了数据库的连接信息,如主机地址、用户名、密码、数据库名等。在这里,我们使用 postgres.Open() 函数创建一个 PostgreSQL 数据库驱动程序,该函数需要一个连接字符串作为参数。&gorm.Config{} 是一个 GORM 配置选项,它告诉 GORM 库如何连接到数据库。
&gorm.Config{} 是 Go 语言中的一个结构体字面量(Struct Literal)。在 GORM 中,gorm.Config 是一个结构体类型,它包含了 GORM 库的配置选项。
& 符号用于获取结构体字面量的地址,即取址符。在这里,&gorm.Config{} 表示获取 gorm.Config 结构体字面量的地址。
{} 符号表示创建一个新的结构体实例,并将其初始化为默认值。在这里,我们创建了一个空的 gorm.Config 结构体实例,并将其传递给 gorm.Open() 函数,以便在打开数据库连接时使用。
因此,&gorm.Config{} 的语法表示创建一个新的 gorm.Config 结构体实例,并将其地址传递给 gorm.Open() 函数,以便在打开数据库连接时使用。
为什么加取址符?
在 GORM 中,gorm.Open() 函数的第二个参数需要传递一个 gorm.Config 类型的指针。因此,如果我们想要将一个 gorm.Config 类型的结构体实例传递给 gorm.Open() 函数,我们需要先获取该结构体实例的地址。
&gorm.Config{} 表示创建一个新的 gorm.Config 结构体实例,并返回该实例的地址。因此,我们可以将 &gorm.Config{} 作为参数传递给 gorm.Open() 函数,以便在打开数据库连接时使用。
总之,加取址符 & 是为了获取 gorm.Config 结构体实例的地址,以便在传递给 gorm.Open() 函数时使用。
常用方法属性
以下是 gorm 包中常用的方法和属性的关键信息表格:
| 方法/属性 | 函数签名 | 描述 |
|---|---|---|
| Open | func Open(dialect string, args ...interface{}) (*DB, error) | 打开数据库连接。返回一个 *DB实例。 |
| DB.Preload | func (db *DB) Preload(query string, args ...interface{}) *DB | 使用预加载方式加载关联的模型数据。 |
| DB.First | func (db *DB) First(dest interface{}, conds ...interface{}) *DB | 从数据库中查询第一个匹配的记录,并将结果存储到 dest中。 |
| DB.Create | func (db *DB) Create(value interface{}) *DB | 在数据库中创建记录。 |
| DB.Save | func (db *DB) Save(value interface{}) *DB | 保存(插入/更新)记录到数据库中。 |
| DB.Delete | func (db *DB) Delete(value interface{}, conds ...interface{}) *DB | 从数据库中删除符合条件的记录。 |
| DB.Where | func (db *DB) Where(query interface{}, args ...interface{}) *DB | 添加查询条件。 |
| DB.Model | func (db *DB) Model(value interface{}) *DB | 指定模型对象,用于构建查询和操作。 |
| DB.Table | func (db *DB) Table(name string) *DB | 指定表名,用于构建查询和操作。 |
| DB.AutoMigrate | func (db *DB) AutoMigrate(dst ...interface{}) error | 根据模型定义自动迁移数据库结构。 |
| DB.Transaction | func (db *DB) Transaction(fc func(tx *gorm.DB) error) error | 开启数据库事务,并执行回调函数。 |
| DB.Raw | func (db *DB) Raw(sql string, values ...interface{}) *DB | 执行原生 SQL 查询。 |
| DB.Exec | func (db *DB) Exec(sql string, values ...interface{}) *DB | 执行 SQL 语句。 |
| DB.Set | func (db *DB) Set(name string, value interface{}) *DB | 设置数据库连接的属性。 |
| DB.Debug | func (db *DB) Debug() *DB | 启用调试模式,输出执行的 SQL 语句。 |
| Model | func Model(value interface{}) *gorm.DB | 指定模型对象,用于构建查询和操作。 |
| Where | func (db *gorm.DB) Where(query interface{}, args ...interface{}) *gorm.DB | 添加查询条件。 |
| Select | func (db *gorm.DB) Select(query string, args ...interface{}) *gorm.DB | 指定要查询的字段。 |
| Joins | func (db *gorm.DB) Joins(query string, args ...interface{}) *gorm.DB | 连接其他表进行查询。 |
| Order | func (db *gorm.DB) Order(value interface{}) *gorm.DB | 指定查询结果的排序方式。 |
| Limit | func (db *gorm.DB) Limit(limit int) *gorm.DB | 指定查询结果的最大记录数。 |
| Offset | func (db *gorm.DB) Offset(offset int) *gorm.DB | 指定查询结果的偏移量。 |
| Scan | func (db *gorm.DB) Scan(dest interface{}) *gorm.DB | 扫描查询结果并将结果存储到 dest中。 |
| Pluck | func (db *gorm.DB) Pluck(column string, value interface{}) *gorm.DB | 从查询结果中提取指定列的值。 |
| FirstOrCreate | func (db *gorm.DB) FirstOrCreate(out interface{}, where ...interface{}) *gorm.DB | 查询第一个匹配记录,如果不存在则创建并返回。 |
| Association | func (db *gorm.DB) Association(column string) *gorm.Association | 获取关联关系。 |
| Preload | func (db *gorm.DB) Preload(column string, conditions ...interface{}) *gorm.DB | 预加载关联数据。 |
| Table | func (db *gorm.DB) Table(name string) *gorm.DB | 指定表名,用于构建查询和操作。 |
| AutoMigrate | func (db *gorm.DB) AutoMigrate(dst ...interface{}) error | 根据模型定义自动迁移数据库结构。 |
| Debug | func (db *gorm.DB) Debug() *gorm.DB | 启用调试模式,输出执行的 SQL 语句。 |
| Error | func (db *gorm.DB) Error() error | 获取最后一次执行操作时的错误信息。 |
| RowsAffected | func (db *gorm.DB) RowsAffected() int64 | 获取最后一次执行操作受影响的行数。 |
| Set | func (db *gorm.DB) Set(key string, value interface{}) *gorm.DB | 设置数据库连接的属性。 |
| Callback | type Callback struct{} | GORM 的回调函数管理器,用于注册和执行回调函数。 |
| Association | type Association struct{} | 关联关系的管理器,用于处理模型之间的关联操作。 |
请注意,这些方法和属性是 gorm 包中常用的,用于进行数据库查询、操作和模型关联等任务的函数和类型。
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
type User struct {
ID uint
Name string
Age int
}
func main() {
// 连接数据库
dsn := "user:password@tcp(127.0.0.1:3306)/database?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
fmt.Println("Failed to connect to database:", err)
return
}
// 创建表结构
err = db.AutoMigrate(&User{})
if err != nil {
fmt.Println("Failed to migrate table:", err)
return
}
// 创建记录
user := User{Name: "Alice", Age: 25}
result := db.Create(&user)
if result.Error != nil {
fmt.Println("Failed to create record:", result.Error)
return
}
fmt.Println("Created record:", user)
// 查询记录
var fetchedUser User
result = db.First(&fetchedUser, "name = ?", "Alice")
if result.Error != nil {
fmt.Println("Failed to fetch record:", result.Error)
return
}
fmt.Println("Fetched record:", fetchedUser)
// 更新记录
result = db.Model(&fetchedUser).Update("Age", 30)
if result.Error != nil {
fmt.Println("Failed to update record:", result.Error)
return
}
fmt.Println("Updated record:", fetchedUser)
// 删除记录
result = db.Delete(&fetchedUser)
if result.Error != nil {
fmt.Println("Failed to delete record:", result.Error)
return
}
fmt.Println("Deleted record:", fetchedUser)
// 其他方法和属性示例
db.Preload("Orders").Find(&user) // 预加载关联数据
db.Model(&user).Association("Orders").Append(&Order{}) // 关联关系操作
db.Where("name = ?", "Alice").Find(&users) // 添加查询条件
db.Table("users").Select("name, age").Find(&result) // 指定查询字段
db.Joins("JOIN orders ON users.id = orders.user_id").Find(&result) // 连接其他表进行查询
db.Order("age desc").Find(&users) // 指定查询结果排序方式
db.Limit(10).Offset(5).Find(&users) // 指定查询结果的限制和偏移
db.Scan(&user) // 扫描查询结果并存储到对象中
db.Pluck("name", &names) // 提取查询结果中的指定列值
db.FirstOrCreate(&user, "name = ?", "Alice") // 查询或创建记录
db.Association("Orders").Find(&orders) // 获取关联关系
db.Debug() // 启用调试模式
db.Error() // 获取最后一次操作的错误信息
db.RowsAffected() // 获取最后一次操作受影响的行数
db.Set("gorm:save_associations", false) // 设置数据库连接属性
}
// 其他定义的结构体和函数
type Order struct {
ID uint
UserID uint
Amount float64
}
func CallbackFunc(db *gorm.DB) {
// 自定义的回调函数逻辑
}
func main() {
db.Callback().Create().Before("gorm:create").Register("custom_callback", CallbackFunc) // 注册自定义回调函数
}
DB类型扩展的方法
gorm框架为DB类型增加了以下常用方法:
Create(value interface{}) error:创建一个新的记录并将其插入数据库中。
type User struct {
ID uint
Name string
Age int
}
user := User{Name: "Tom", Age: 18}
result := db.Create(&user)
Save(value interface{}) error:如果记录已经存在,则更新记录;否则,创建一个新的记录。First(out interface{}, where ...interface{}) error:获取第一个匹配条件的记录并将其赋值给out。Find(out interface{}, where ...interface{}) error:获取所有匹配条件的记录并将其赋值给out。
var users []User
result2 := db.Find(&users)
Update(column string, value interface{}) error:更新指定列的值。
result3 := db.Model(&user).Update("Name", "Jerry")
Updates(values interface{}, ignoreProtectedAttrs ...bool) error:使用map或struct更新记录的多个列。Delete(value interface{}, where ...interface{}) error:删除与条件匹配的记录。
//会删除所有满足user条件{Name: "Tom", Age: 18}的数据
result4 := db.Delete(&user)
Model(value interface{}) *DB:为DB类型创建一个新的查询。
//&user代表操作以及存在的user对象
result3 := db.Model(&user).Update("Name", "Jerry")
Table(name string) *DB:指定要查询的表名。Where(query interface{}, args ...interface{}) *DB:指定查询条件。Order(value interface{}, reorder ...bool) *DB:指定查询结果的排序方式。Limit(limit int) *DB:限制查询结果的数量。Offset(offset int) *DB:指定查询结果的偏移量。Select(query interface{}, args ...interface{}) *DB:指定要查询的列。Count(value interface{}) *DB:计算查询结果的数量。
这些方法可以通过 DB 类型调用,例如:
db := gorm.Open(...)
var user User
db.First(&user, "name = ?", "Alice")
db.Model(&user).Update("age", 30)
Model
db.Model() 方法的原型如下:
func (db *DB) Model(value interface{}) *DB
其中,db 是一个 *gorm.DB 类型的指针,表示数据库连接,value 是一个任意类型的参数,表示要操作的模型。
该方法返回一个 *gorm.DB 类型的指针,可以通过链式调用该指针上的其他方法来进行后续的操作。
在 GORM 中,db.Model() 方法用于指定要操作的模型。它的作用是将当前数据库连接与指定的模型关联起来,以便后续的操作可以针对该模型进行。
db.Model() 方法接受一个模型作为参数,例如:
db.Model(&User{})
上面的代码将当前数据库连接与 User 模型关联起来,以便后续的操作可以针对 User 模型进行。可以通过链式调用 db.Model() 方法来对同一个模型进行多个操作,例如:
db.Model(&User{}).Where("name = ?", "Alice").Update("email", "alice@example.com")
上面的代码将当前数据库连接与 User 模型关联起来,并使用 Where() 方法指定查询条件,然后使用 Update() 方法更新满足条件的记录的 email 字段。
db.Model(&User{})与db.Model(User{})
在 GORM 中,db.Model(&User{}) 和 db.Model(User{}) 是有区别的。
db.Model(&User{}) 传递的是 *User 类型的指针,表示要操作的是一个已经存在的 User 对象,而 db.Model(User{}) 传递的是 User 类型的值,表示要操作的是一个新的、未经过初始化的 User 对象。
因此,如果你想要操作已经存在的 User 对象,应该使用 db.Model(&User{}),如果你想要操作新的、未经过初始化的 User 对象,应该使用 db.Model(User{})。
错误用法:db.Model(User)
db.Model(User) 是不正确的用法,因为 Model 方法需要传入一个指针类型的参数,而 User 是一个结构体类型,不是指针类型。如果你要操作 User 对象,应该使用 &User{} 或 new(User) 创建一个指向 User 对象的指针,然后传递给 Model 方法。
需要传入一个值,不能传入一个类型。。
AutoMigrate
type User struct {
ID uint
Name string
Age int
}
err3 := db.AutoMigrate(&User{})
db.AutoMigrate(&User{}) 是 gorm 中用于自动迁移数据库的方法。它的作用是根据 User 结构体的定义自动创建对应的数据表,并自动更新表结构。
具体来说,AutoMigrate 方法会执行以下操作:
- 检查数据库中是否已经存在名为
users的表。如果不存在,则创建该表。 - 检查表结构是否与
User结构体的定义匹配。如果不匹配,则根据User结构体的定义自动更新表结构。
对于 User 结构体,AutoMigrate 方法会创建一个名为 users 的数据表,并为该表创建 id、name 和 age 三个字段。如果该表已经存在,AutoMigrate 方法会检查表结构是否与 User 结构体的定义匹配,并自动更新表结构以保持一致。
AutoMigrate 方法可以一次性自动迁移多个结构体,例如:
db.AutoMigrate(&User{}, &Product{}, &Order{})
这样就会自动创建 users、products 和 orders 三个数据表,并为每个表创建对应的字段。
需要注意的是,AutoMigrate 方法只会创建缺失的表和字段,不会删除多余的表和字段。如果需要删除多余的表和字段,可以使用 db.DropTableIfExists(&User{}) 和 db.Migrator().DropColumn(&User{}, "Age") 等方法。
Create、CreateInBatches
db.Create(&user) 是 GORM 中用于向数据库中插入一条记录的方法。其中,&user 是一个指向 User 结构体的指针,表示要插入的数据。
下面是一个示例:
user := User{Name: "Tom", Age: 18, Email: "tom@example.com"}
result := db.Create(&user)
if result.Error != nil {
// 处理错误
}
在这个示例中,我们创建了一个名为 user 的 User 结构体,并设置了 Name、Age 和 Email 字段的值。然后,我们调用了 db.Create(&user) 方法将 user 对象插入到数据库中。如果插入过程中发生错误,result.Error 将不为 nil,我们可以在代码中处理这个错误。
需要注意的是,db.Create(&user) 方法会将 user 对象的所有字段都插入到数据库中,包括 ID 字段。如果 ID 字段没有设置值,GORM 会自动生成一个唯一的值作为 ID。
生成ID的规则:
如果你使用 GORM 默认的 ID 字段,它会自动为每个新插入的记录生成一个唯一的 ID 值。这个 ID 值可以是一个整数、字符串或 UUID 等类型,具体的类型取决于你在模型中定义的字段类型。
默认情况下,GORM 使用自增的方式生成整数类型的 ID 值。也就是说,每当你插入一条新记录时,GORM 会自动为这条记录分配一个比前一条记录的 ID 值大 1 的值。如果你希望使用其他类型的 ID 值,可以在模型中定义一个对应的字段,并在插入记录时手动为其赋值。
下面是一个示例,展示了如何手动为 ID 字段赋值:
type User struct {
ID string `gorm:"primary_key"`
Name string
Email string
}
user := User{
ID: "123",
Name: "Tom",
Email: "tom@example.com",
}
result := db.Create(&user)
if result.Error != nil {
// 处理错误
}
在这个示例中,我们手动为 ID 字段赋值为 "123",然后调用 db.Create(&user) 方法将 user 对象插入到数据库中。注意,这里的 ID 字段使用了 gorm:"primary_key" 标签,表示它是这个模型的主键。如果你不希望使用 ID 字段作为主键,可以在模型中定义一个其他的字段,并使用 gorm:"primary_key" 标签来指定它。
另外,如果要插入多条记录,可以使用 db.CreateInBatches 方法,它可以一次性插入多条记录,从而提高插入的效率。
db.CreateInBatches() 是 GORM 提供的一个批量插入数据的方法。它可以一次性插入多条记录,从而提高插入数据的效率。
CreateInBatches() 方法的函数签名如下:
func (db *DB) CreateInBatches(value interface{}, batchSize int) (result *DB)
其中,value 参数表示要插入的数据,可以是一个结构体切片或指针切片。batchSize 参数表示每批次插入的记录数。
下面是一个示例,展示了如何使用 CreateInBatches() 方法批量插入数据:
type User struct {
ID uint
Name string
Email string
}
users := []User{
{Name: "Tom", Email: "tom@example.com"},
{Name: "Jerry", Email: "jerry@example.com"},
{Name: "Mike", Email: "mike@example.com"},
{Name: "Lucy", Email: "lucy@example.com"},
}
result := db.CreateInBatches(&users, 2)
if result.Error != nil {
// 处理错误
}
在这个示例中,我们定义了一个 User 结构体,并创建了一个包含 4 条记录的切片。然后,我们调用 db.CreateInBatches(&users, 2) 方法将这些记录分成 2 批次插入到数据库中。这意味着,每批次插入 2 条记录,一共需要插入 2 批次。
需要注意的是,CreateInBatches() 方法只适用于插入数据,不能用于更新数据或删除数据。如果你需要批量更新或删除数据,可以考虑使用 db.Model().Updates() 或 db.Delete() 方法。
DropTableIfExists、DropColumn
//删除表
db.DropTableIfExists(&User{})
//删除字段
db.Migrator().DropColumn(&User{}, "Age")
Delete
db.Delete 是 GORM 框架中的一个方法,用于从数据库中删除符合条件的记录。它的基本语法如下:
db.Delete(&user)
其中,db 是一个 *gorm.DB 类型的对象,表示要进行删除操作的数据库连接;&user 是一个指向要删除记录的指针。
你可以通过在 Delete 方法中传入一个条件表达式来删除符合条件的记录。例如,下面的代码将删除 age 大于等于 18 的所有用户记录:
db.Where("age >= ?", 18).Delete(&User{})
这里,Where 方法指定了一个条件表达式,? 是占位符,它将被后面的参数 18 替换。Delete 方法的参数是一个指向要删除记录的指针,这里传入的是 &User{},表示要删除 User 表中符合条件的所有记录。
使用参数2指定条件
Delete 方法的第二个参数 where 是一个可变参数,用于指定删除记录的条件。它可以是一个字符串,也可以是一个结构体、map、slice 等类型。如果省略该参数,则会删除表中的所有记录。
当 where 参数是一个字符串时,它表示一个 SQL 条件表达式,例如:
db.Delete(&User{}, "age >= ?", 18)
这条语句将删除 User 表中所有 age 大于等于 18 的记录。
当 where 参数是一个结构体、map、slice 等类型时,它表示一个查询条件。例如:
db.Delete(&User{}, map[string]interface{}{"name": "Tom", "age": 18})
这条语句将删除 User 表中所有 name 为 "Tom" 且 age 为 18 的记录。
如果需要同时指定多个条件,可以使用 AND 或 OR 连接它们,例如:
db.Delete(&User{}, "name = ? AND age >= ?", "Tom", 18)
这条语句将删除 User 表中所有 name 为 "Tom" 且 age 大于等于 18 的记录。
需要注意的是,Delete 方法返回的是一个 error 类型的值,如果执行删除操作时发生错误,将返回相应的错误信息。
Update、Updates
result3 := db.Model(&user).Update("Name", "Jerry")
db.Model(&user).Update("Name", "Jerry") 是 gorm 中用于更新数据的方法。它的作用是将 user 对象在数据库中对应的记录的 Name 字段更新为 "Jerry"。
具体来说,Model(&user) 方法用于指定要更新的数据表和记录。在这个例子中,它会根据 user 对象的类型自动推断出要更新的数据表为 users,并根据 user 对象的 ID 属性自动推断出要更新的记录。
Update("Name", "Jerry") 方法用于指定要更新的字段和值。在这个例子中,它会将 users 表中 ID 为 user.ID 的记录的 Name 字段更新为 "Jerry"。
Update 方法还支持同时更新多个字段,例如:
db.Model(&user).Updates(User{Name: "Jerry", Age: 30})
这样就会将 users 表中 ID 为 user.ID 的记录的 Name 字段更新为 "Jerry",Age 字段更新为 30。
需要注意的是,Update 方法只会更新指定的字段,不会更新其他字段。如果需要更新所有字段,可以使用 Updates 方法。另外,如果要更新的字段值与原来的值相同,Update 方法不会执行任何操作。
Updates 方法与 Update 方法类似,都是用于更新数据的方法,但是 Updates 方法可以同时更新多个字段。下面是一个使用 Updates 方法更新数据的例子:
//会更新所有字段,而不仅仅是 User结构体中设置了值的字段。应该可以加参数来忽略更新某些字段
db.Model(&user).Updates(User{Name: "Jerry", Age: 30})
在这个例子中,User{Name: "Jerry", Age: 30} 是一个 User 类型的结构体,它的 Name 字段被设置为 "Jerry",Age 字段被设置为 30。Updates 方法会将 users 表中 ID 为 user.ID 的记录的 Name 和 Age 字段更新为对应的值。
需要注意的是,Updates 方法会更新所有指定的字段,而不仅仅是 User 结构体中设置了值的字段。如果要更新的字段值与原来的值相同,Updates 方法不会执行任何操作。
更新受保护的字段
在 GORM 中,Updates() 方法用于更新模型的某些字段。第二个参数 ignoreProtectedAttrs 是一个可选参数,用于指定是否忽略受保护的属性。默认情况下,受保护的属性是不会被更新的,除非在模型中明确指定了这些属性可以被更新。如果将 ignoreProtectedAttrs 参数设置为 true,则受保护的属性也会被更新。
以下是一个使用 Updates() 方法的示例:
// 定义一个模型
type User struct {
ID uint `gorm:"primaryKey"`
Name string `gorm:"not null"`
Email string `gorm:"not null;unique"`
Password string `gorm:"not null"`
CreatedAt time.Time
UpdatedAt time.Time
}
// 更新模型的某些字段
err := db.Model(&User{}).Where("id = ?", 1).Updates(map[string]interface{}{
"name": "Alice",
"email": "alice@example.com",
}, true).Error
if err != nil {
// 处理错误
}
在上面的示例中,Updates() 方法被用于更新 User 模型的 name 和 email 字段。第二个参数 true 指定了忽略受保护的属性。这意味着即使 User 模型中的 Password 字段被标记为受保护的属性,它也会被更新。
为什么参数2是ignoreProtectedAttrs ...bool,而不是ignoreProtectedAttrs bool
在 Golang 中,参数列表中的 ... 表示该参数是可变参数。可变参数可以接受任意数量的参数,这些参数会被打包成一个切片。在 GORM 中,ignoreProtectedAttrs 参数就是一个可变参数,因为它可以接受零个或多个布尔值作为参数。
如果 ignoreProtectedAttrs 参数的类型是 bool,那么它只能接受一个布尔值作为参数。但是,GORM 的 Updates() 方法需要支持忽略多个受保护的属性,因此需要一个可变参数来接受多个布尔值。
在调用 Updates() 方法时,可以传递一个或多个布尔值作为 ignoreProtectedAttrs 参数。例如,以下代码演示了如何同时更新多个模型并忽略它们的受保护属性:
err := db.Model(&User{}).Updates(
User{Name: "Alice", Email: "alice@example.com"},
User{Name: "Bob", Email: "bob@example.com"},
true, true,
).Error
if err != nil {
// 处理错误
}
在上面的示例中,Updates() 方法被用于同时更新两个 User 模型,并忽略它们的受保护属性。最后的两个布尔值表示忽略受保护的属性。
Save
db.Save() 是 GORM 提供的一个保存数据的方法。它可以用于插入新数据或更新已有数据,根据数据的主键或唯一索引来自动判断是插入还是更新操作。
Save() 方法的函数签名如下:
func (db *DB) Save(value interface{}) (result *DB)
其中,value 参数表示要保存的数据,可以是一个结构体或指针。如果该数据已经存在于数据库中,Save() 方法会自动更新该数据;否则,它会自动插入一条新记录。
下面是一个示例,展示了如何使用 Save() 方法插入新数据或更新已有数据:
type User struct {
ID uint
Name string
Email string
}
// 插入新数据
user1 := User{Name: "Tom", Email: "tom@example.com"}
result := db.Save(&user1)
if result.Error != nil {
// 处理错误
}
// 更新已有数据
user2 := User{ID: 1, Name: "Jerry", Email: "jerry@example.com"}
result = db.Save(&user2)
if result.Error != nil {
// 处理错误
}
在这个示例中,我们定义了一个 User 结构体,并创建了两个实例 user1 和 user2。第一个实例表示要插入一条新记录,第二个实例表示要更新 ID 为 1 的记录。然后,我们调用 db.Save(&user1) 方法将 user1 插入到数据库中;接着,我们调用 db.Save(&user2) 方法更新 ID 为 1 的记录。
需要注意的是,如果数据的主键或唯一索引不存在,Save() 方法会自动插入一条新记录。如果你想强制更新数据,可以使用 db.Model().Updates() 方法或 db.Model().Update() 方法。
First
db.First() 是 GORM 提供的一个查询方法,用于查询符合条件的第一条记录。它的函数签名如下:
func (db *DB) First(dest interface{}, conds ...interface{}) (result *DB)
其中,dest 参数表示查询结果将被存储到的目标对象,可以是一个结构体或指针;conds 参数表示查询条件,可以是一个字符串或结构体。如果省略 conds 参数,First() 方法将返回表中的第一条记录。
下面是一个示例,展示了如何使用 First() 方法查询符合条件的第一条记录:
type User struct {
ID uint
Name string
Email string
}
// 查询 ID 为 1 的用户
var user User
result := db.First(&user, 1)
if result.Error != nil {
// 处理错误
}
// 查询名字为 Tom 的用户
result = db.First(&user, "name = ?", "Tom")
if result.Error != nil {
// 处理错误
}
在这个示例中,我们定义了一个 User 结构体,并创建了一个变量 user。然后,我们调用 db.First(&user, 1) 方法查询 ID 为 1 的用户,并将结果存储到 user 变量中;接着,我们调用 db.First(&user, "name = ?", "Tom") 方法查询名字为 Tom 的用户。
需要注意的是,如果查询结果为空,First() 方法将返回 record not found 错误。如果你不想返回错误,可以使用 db.Where().First() 方法或 db.Take() 方法,它们在查询结果为空时会返回零值。
Where
db.First() 方法可以支持复杂查询,可以通过链式调用 Where()、Order()、Limit() 等方法来添加查询条件、排序和限制记录数。下面是一个示例,展示了如何使用 db.First() 方法进行复杂查询:
type User struct {
ID uint
Name string
Email string
Age int
}
// 查询年龄最小的用户
var user User
result := db.Order("age asc").First(&user)
if result.Error != nil {
// 处理错误
}
// 查询名字为 Tom 的年龄最小的用户
result = db.Where("name = ?", "Tom").Order("age asc").First(&user)
//查询名字为 Tom,年龄为 12 的用户
//询条件中的 ? 占位符将会被传递给 Where() 方法的第二个参数,按照顺序依次替换
result := db.Where("name = ? AND age = ?", "Tom", 12).First(&user)
if result.Error != nil {
// 处理错误
}
//用结构体指定查询条件
db.Where(map[string]interface{}{"age": 18, "name": "Alice"}).Find(&users)
在这个示例中,我们定义了一个 User 结构体,并创建了一个变量 user。然后,我们调用 db.Order("age asc").First(&user) 方法查询年龄最小的用户,并将结果存储到 user 变量中;接着,我们调用 db.Where("name = ?", "Tom").Order("age asc").First(&user) 方法查询名字为 Tom 的年龄最小的用户。
需要注意的是,如果查询结果为空,First() 方法将返回 record not found 错误。如果你不想返回错误,可以使用 db.Where().First() 方法或 db.Take() 方法,它们在查询结果为空时会返回零值。
Order
在 GORM 中,可以使用 DB.Order 方法指定查询结果的排序方式。该方法的用法如下:
func (db *DB) Order(value interface{}, reorder ...bool) *DB
其中,value 参数是排序规则,可以是一个字符串或一个 map[string]interface{} 类型的结构体。reorder 参数是可选的,用于指定是否覆盖之前的排序规则。
例如,假设要查询 users 表中所有用户,并按照 age 字段升序排序,可以使用以下代码:
db := gorm.Open("mysql", "user:password@tcp(127.0.0.1:3306)/database_name?charset=utf8mb4&parseTime=True&loc=Local")
var users []User
db.Order("age asc").Find(&users)
在上面的代码中,首先使用 gorm.Open 方法打开了一个 MySQL 数据库连接,并将其赋值给 db 变量。然后,使用 db.Order 方法指定查询结果按照 age 字段升序排序,并将查询结果保存到 users 变量中。
除了字符串形式的排序规则,还可以使用 map[string]interface{} 类型的结构体指定排序规则。例如,以下代码与上面的代码功能相同:
db.Order(map[string]interface{}{"age": "asc"}).Find(&users)
在上面的代码中,使用了一个 map[string]interface{} 类型的结构体指定排序规则。其中,map 中的键为字段名,值为排序方式。这样可以更清晰地指定排序规则。
参数2用法
reorder 参数用于指定是否覆盖之前的排序规则。如果不指定该参数,默认值为 false,即不覆盖之前的排序规则。
例如,假设先使用 Order 方法指定了一个排序规则,然后又使用 Order 方法指定了另一个排序规则,可以通过设置 reorder 参数来控制是否覆盖之前的排序规则。
db.Order("age asc").Order("name desc", true).Find(&users)
在上面的代码中,第一个 Order 方法指定了按照 age 字段升序排序,第二个 Order 方法指定了按照 name 字段降序排序,并将 reorder 参数设置为 true,表示覆盖之前的排序规则。这样,查询结果将先按照 name 字段降序排序,然后再按照 age 字段升序排序。
需要注意的是,如果多次使用 Order 方法指定了多个排序规则,而且其中某个排序规则的 reorder 参数设置为 true,那么之前指定的所有排序规则都会被覆盖。
Limit、Offset
DB.Limit 是 GORM 提供的一个链式调用方法,用于指定查询结果的最大返回行数。它的语法如下:
func (db *DB) Limit(limit int) *DB
其中,limit 参数表示最大返回行数。例如,我们可以这样使用 DB.Limit 方法来查询前 10 条用户记录:
db.Limit(10).Find(&users)
这样,查询结果就会最多返回 10 条用户记录。需要注意的是,如果查询结果的总行数不足 10 行,那么就会返回所有的行。另外,如果我们想要指定查询结果的偏移量,可以使用 DB.Offset 方法。例如,如果我们想要查询从第 11 行开始的 10 条用户记录,可以这样写:
db.Offset(10).Limit(10).Find(&users)
这样,查询结果就会从第 11 行开始,最多返回 10 条用户记录。
Find
DB.Find() 是 GORM 中的一个方法,用于查询符合条件的多条记录。
使用 DB.Find() 方法需要传入一个指向切片的指针,GORM 会将查询结果填充到这个切片中。同时,你也需要提供查询条件。
下面是一个使用 DB.Find() 方法的示例:
type User struct {
ID uint
Name string
Email string
Age int
}
var users []User
result := db.Where("age > ?", 18).Find(&users)
if result.Error != nil {
// 处理错误
}
在这个示例中,我们查询了年龄大于 18 岁的所有用户,并将查询结果填充到了 users 切片中。
需要注意的是,如果查询结果为空,Find() 方法会返回一个空的切片,而不是一个错误。
Table
在 GORM 中,可以使用 DB.Table 方法指定要操作的数据库表。该方法的用法如下:
func (db *DB) Table(name string) *DB
其中,name 参数是要操作的数据库表的名称。该方法会返回一个新的 *DB 对象,该对象指定了要操作的数据库表。
例如,假设有一个名为 users 的数据库表,可以使用以下代码指定要操作该表:
db := gorm.Open("mysql", "user:password@tcp(127.0.0.1:3306)/database_name?charset=utf8mb4&parseTime=True&loc=Local")
usersDB := db.Table("users")
在上面的代码中,首先使用 gorm.Open 方法打开了一个 MySQL 数据库连接,并将其赋值给 db 变量。然后,使用 db.Table 方法指定要操作的数据库表为 users,并将返回的新的 *DB 对象赋值给 usersDB 变量。
接下来,就可以使用 usersDB 对象进行各种数据库操作了,例如查询、插入、更新、删除等。
Select
DB.Select 是 GORM 提供的一个链式调用方法,用于指定查询结果需要返回的字段。它的语法如下:
func (db *DB) Select(query interface{}, args ...interface{}) *DB
其中,query 参数表示需要返回的字段,可以是一个字符串,也可以是一个结构体。如果是一个字符串,那么它应该是一个逗号分隔的字段列表,例如:
db.Select("name, age, email").Find(&users)
这样,查询结果就只会返回 name、age 和 email 这三个字段的值。如果 query 参数是一个结构体,那么 GORM 会根据结构体的字段信息自动生成需要返回的字段列表,例如:
type User struct {
ID uint
Name string
Age int
Email string
}
var user User
db.Select(&user).First(&user)
这样,查询结果就只会返回 ID、Name、Age 和 Email 这四个字段的值。需要注意的是,如果 query 参数是一个结构体指针,那么 GORM 会根据结构体的类型自动生成表名(自动生成的表名可能是User)。如果表名与结构体类型不同,可以使用 DB.Table 方法来指定表名,例如:
db.Table("my_users").Select(&user).First(&user)
这样,GORM 就会在 my_users 表中查询数据,并返回 ID、Name、Age 和 Email 这四个字段的值。
Count
DB.Count 是 GORM 提供的一个链式调用方法,用于查询符合条件的记录数量。它的语法如下:
func (db *DB) Count(count *int64) *DB
其中,count 参数是一个 int64 类型的指针,用于存储查询结果的数量。例如:
var count int64
db.Model(&User{}).Where("age > ?", 18).Count(&count)
这样,就会查询出年龄大于 18 岁的用户数量,并将结果存储在 count 变量中。需要注意的是,DB.Count 方法必须与 DB.Model 或 DB.Table 方法一起使用,以指定查询的数据表。