介绍

在开发现代应用程序时,数据库操作是不可避免的一部分。而使用对象关系映射(ORM)框架可以极大地简化数据库操作。在Go语言中,GORM是一个功能强大且使用广泛的ORM库,它支持多种数据库,如MySQL、PostgreSQL、SQLite和SQL Server等。本文将详细介绍GORM的使用方法和最佳实践。

GORM 官方文档地址

安装

安装GORM

1
go get -u gorm.io/gorm

安装数据库驱动

根据你使用的数据库,还需要安装相应的驱动:

1
2
3
4
5
6
7
8
9
10
11
# MySQL
go get -u gorm.io/driver/mysql

# PostgreSQL
go get -u gorm.io/driver/postgres

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

# SQL Server
go get -u gorm.io/driver/sqlserver

连接数据库

MySQL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main

import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)

func main() {
dsn := "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}

// 现在你可以使用db对象进行数据库操作了
}

PostgreSQL

1
2
dsn := "host=localhost user=gorm password=gorm dbname=gorm port=9920 sslmode=disable TimeZone=Asia/Shanghai"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})

SQLite

1
db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{})

模型定义

在GORM中,模型是与数据库表对应的Go结构体。下面是一个简单的模型定义示例:

1
2
3
4
5
6
7
8
9
10
type User struct {
ID uint `gorm:"primaryKey"`
Name string
Email string `gorm:"uniqueIndex"`
Age int
Birthday time.Time
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}

字段标签

GORM支持多种字段标签,用于自定义字段的数据库行为:

  • gorm:"column:name" - 指定字段对应的表列名
  • gorm:"primaryKey" - 将字段设置为主键
  • gorm:"uniqueIndex" - 为字段创建唯一索引
  • gorm:"default:value" - 设置字段的默认值
  • gorm:"type:varchar(100)" - 指定字段的数据库类型
  • gorm:"not null" - 设置字段为非空
  • gorm:"size:255" - 设置字段的大小
  • gorm:"-" - 忽略该字段

示例:

1
2
3
4
5
6
7
type Product struct {
ID uint `gorm:"primaryKey"`
Code string `gorm:"column:product_code;type:varchar(100);uniqueIndex;not null"`
Price float64
CreatedAt time.Time
UpdatedAt time.Time
}

表操作

自动迁移

GORM提供了自动迁移功能,可以根据模型定义自动创建或更新表结构:

1
2
// 自动迁移
db.AutoMigrate(&User{}, &Product{})

创建表

1
2
// 创建表
db.Migrator().CreateTable(&User{})

检查表是否存在

1
2
// 检查表是否存在
exists := db.Migrator().HasTable(&User{})

删除表

1
2
// 删除表
db.Migrator().DropTable(&User{})

CRUD操作

创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 创建记录
user := User{Name: "John", Age: 18, Email: "john@example.com"}
result := db.Create(&user)

// 检查错误
if result.Error != nil {
// 处理错误
}

// 获取受影响的行数
rowsAffected := result.RowsAffected

// 批量创建
users := []User{
{Name: "John", Age: 18, Email: "john@example.com"},
{Name: "Jane", Age: 20, Email: "jane@example.com"},
}
db.Create(&users)

查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 查询单条记录
var user User
db.First(&user, 1) // 查询ID为1的记录
db.First(&user, "name = ?", "John") // 条件查询

// 查询多条记录
var users []User
db.Find(&users) // 查询所有记录
db.Where("age > ?", 18).Find(&users) // 条件查询

// 查询指定字段
db.Select("name", "age").Find(&users)

// 排序
db.Order("age desc, name").Find(&users)

// 分页
db.Limit(10).Offset(0).Find(&users)

// 分组
db.Model(&User{}).Select("count(id)").Group("age").Find(&result)

// 连接
db.Model(&User{}).Joins("JOIN emails ON emails.user_id = users.id").Find(&users)

更新

1
2
3
4
5
6
7
8
9
10
11
// 更新单个字段
db.Model(&user).Update("name", "New Name")

// 更新多个字段
db.Model(&user).Updates(User{Name: "New Name", Age: 20})

// 更新指定字段
db.Model(&user).Select("name", "age").Updates(User{Name: "New Name", Age: 20})

// 批量更新
db.Model(&User{}).Where("age > ?", 18).Update("name", "Adult")

删除

1
2
3
4
5
6
7
8
// 删除记录
db.Delete(&user)

// 条件删除
db.Where("age > ?", 18).Delete(&User{})

// 批量删除
db.Delete(&User{}, []int{1, 2, 3})

关联

GORM支持多种关联关系,如一对一、一对多、多对多等。

一对一关联

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
type User struct {
ID uint
Name string
CreditCard CreditCard
}

type CreditCard struct {
ID uint
Number string
UserID uint
}

// 自动创建关联
user := User{
Name: "John",
CreditCard: CreditCard{Number: "1234567890"},
}
db.Create(&user)

// 预加载关联
var user User
db.Preload("CreditCard").First(&user, 1)

一对多关联

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
type User struct {
ID uint
Name string
Orders []Order
}

type Order struct {
ID uint
Amount float64
UserID uint
}

// 自动创建关联
user := User{
Name: "John",
Orders: []Order{
{Amount: 100.0},
{Amount: 200.0},
},
}
db.Create(&user)

// 预加载关联
var user User
db.Preload("Orders").First(&user, 1)

多对多关联

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
type User struct {
ID uint
Name string
Languages []Language `gorm:"many2many:user_languages;"`
}

type Language struct {
ID uint
Name string
Users []User `gorm:"many2many:user_languages;"`
}

// 自动创建关联
user := User{
Name: "John",
Languages: []Language{
{Name: "Go"},
{Name: "Python"},
},
}
db.Create(&user)

// 预加载关联
var user User
db.Preload("Languages").First(&user, 1)

事务

GORM支持事务操作,确保数据库操作的原子性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 自动事务
err := db.Transaction(func(tx *gorm.DB) error {
// 在事务中执行操作
if err := tx.Create(&user).Error; err != nil {
// 返回任何错误都会回滚事务
return err
}

if err := tx.Create(&order).Error; err != nil {
return err
}

// 返回nil提交事务
return nil
})

// 手动事务
tx := db.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()

if err := tx.Create(&user).Error; err != nil {
tx.Rollback()
return err
}

if err := tx.Create(&order).Error; err != nil {
tx.Rollback()
return err
}

return tx.Commit().Error

钩子

GORM提供了多个钩子方法,允许你在创建、更新、查询和删除操作前后执行自定义逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
type User struct {
ID uint
Name string
Email string
}

// 创建前
func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
// 验证邮箱
if !isValidEmail(u.Email) {
return errors.New("invalid email")
}
return
}

// 创建后
func (u *User) AfterCreate(tx *gorm.DB) (err error) {
// 发送欢迎邮件
return sendWelcomeEmail(u.Email)
}

可用的钩子方法有:

  • BeforeSave
  • AfterSave
  • BeforeCreate
  • AfterCreate
  • BeforeUpdate
  • AfterUpdate
  • BeforeDelete
  • AfterDelete
  • AfterFind

性能优化

批量插入

当需要插入大量记录时,使用批量插入可以提高性能:

1
2
3
4
5
6
7
8
var users = []User{
{Name: "John"},
{Name: "Jane"},
// ... 更多用户
}

// 分批次插入,每批100条
db.CreateInBatches(users, 100)

查询优化

使用索引和合适的查询条件可以提高查询性能:

1
2
3
4
5
6
7
8
// 使用索引字段查询
db.Where("email = ?", "john@example.com").First(&user)

// 只查询需要的字段
db.Select("name", "age").Find(&users)

// 使用Limit限制结果数量
db.Limit(10).Find(&users)

总结

GORM是一个功能强大且易于使用的Go ORM库,它提供了丰富的功能,如自动迁移、CRUD操作、关联关系、事务支持等。通过使用GORM,你可以专注于业务逻辑,而不是底层的SQL操作。本文介绍了GORM的基本用法和最佳实践,希望对你有所帮助。在实际开发中,建议结合GORM的官方文档进行更深入的学习和使用。