使用 GORM 连接数据库
ORM (Object-Relational Mapping) 是一种程序设计技术,用于在关系数据库和面向对象的编程语言之间转换数据。GORM 是 Go 的一款常用 ORM 库,能够简化数据库的交互,通过映射 Go 结构体与数据库表,实现对象与关系型数据库之间的转换。
安装 GORM
在 Go 项目中使用 GORM 需要通过 go get 安装:
go get -u gorm.io/gorm
同时,如果使用 MySQL,安装 MySQL 的驱动:
go get -u gorm.io/driver/mysql
定义模型
GORM 通过将 Go 结构体映射到数据库表来简化数据库交互。可以通过定义结构体来表示数据库表。下面是一个简单的例子:
定义结构体
type Student struct {
ID uint `gorm:"primaryKey"` //作为主键
Name string `gorm:"size:255"`
Class int `gorm:"column:班级"`
Score int `gorm:"default:0"`
}
在这个结构体中,gorm.Model 包含了 ID、CreatedAt、UpdatedAt 和 DeletedAt(支持软删除)字段。Name 和 Sum 是自定义的字段。
自定义表名
通过实现 TableName 接口,GORM 会默认根据结构体名生成表名,如果需要自定义表名,可以实现该接口:
func (s Student) TableName() string {
return "students"
}
自定义主键与软删除支持
GORM 会自动为结构体生成 ID 作为主键。如果需要自定义主键或进行软删除(使用 DeletedAt 字段),可以如下配置:
type Model struct {
ID uint `gorm:"primarykey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"` // 支持软删除
}
连接数据库
通过 gorm.Open 方法连接数据库,并通过 AutoMigrate 自动迁移数据库表结构。下面是连接 MySQL 数据库并自动创建表的示例:
dsn := "user:password@tcp(127.0.0.1:3306)/testdb?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
// 自动迁移表结构
err = db.AutoMigrate(&Plant{})
if err != nil {
log.Fatalf("Failed to migrate database: %v", err)
}
创建记录
插入数据
通过 Create 方法插入单条或多条记录:
s1 := []*Student{
{ID: 1, Name: "Zhang", Class: 2024},
{ID: 2, Name: "Li", Class: 2023, Score: 100},
{ID: 3, Name: "Wang", Class: 2022, Score: 90},
}
db.Create(s1) // 插入数据,传入结构体指针
使用 Upsert(插入或更新)
GORM 支持 Upsert,即如果记录已存在则更新,否则插入。可以通过 OnConflict 子句来解决冲突:
result := db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "ID"}}, // 指定冲突的列
DoUpdates: clause.AssignmentColumns([]string{"Score"}), // 更新的字段
}).Create(&s2)
if result.Error != nil {
log.Println(result.Error)
}
查询记录
查询单个记录
使用 First、Take 或 Last 查询一条记录:
var s3 Student
db.First(&s3, 3) // 根据主键查询
fmt.Println(s3)
var s4 Student
db.Where("Score =?", 100).First(&s4) // 条件查询
fmt.Println(s4)
查询多个记录
使用 Find 查询多条记录:
var s5 []Student
db.Where("Score > ?", 0).Find(&s5) // 查询所有成绩大于 0 的学生
var s6 []Student
db.Where("Score > ? AND Class = ?", 0, 2024).Find(&s6) // 条件查询
fmt.Println(s5, s6)
查询某些字段
只查询某些字段,可以通过 Select 来实现:
var names []string
db.Model(&Student{}).Select("Name").Where("Class = ?", 2024).Pluck("Name", &names)
fmt.Println(names)
更新数据
更新特定字段
通过 Updates 方法更新指定字段:
db.Where("name = ?", "qi").Updates(Student{Score: 95}) // 部分字段更新
也可以使用 map 更新字段:
db.Where("name = ?", "Li").Updates(map[string]interface{}{"score": 95})
更新所有字段
使用 Save 方法更新记录(包括所有字段):
var s3 Student
db.First(&s3, 3) // 根据主键查询
s3.Class = 2025
s3.Name = "qi"
db.Save(&s3) // 全字段更新
删除记录
物理删除
物理删除通过 Delete 方法:
db.Delete(&Student{}, 1) // 根据主键删除
软删除
软删除通过 Delete 方法,要求表中有 DeletedAt 字段:
db.Delete(&Student{}, 1) // 软删除
// 忽略软删除,进行硬删除
db.Unscoped().Delete(&Student{}, 1)
删除时,GORM 会自动将 DeletedAt 字段设置为当前时间,从而不删除实际数据,保持数据完整性。
Hooks
GORM 支持模型钩子,可以在创建、更新或删除记录时执行自定义逻辑。常用的钩子有:
BeforeCreate: 在创建记录之前调用。AfterCreate: 在创建记录之后调用。BeforeUpdate: 在更新记录之前调用。AfterUpdate: 在更新记录之后调用。BeforeDelete: 在删除记录之前调用。AfterDelete: 在删除记录之后调用。
例如,定义 BeforeCreate 钩子:
func (p *Student) BeforeCreate(tx *gorm.DB) (err error) {
// 在创建记录之前,执行某些逻辑
if p.Name == "" {
return errors.New("Name cannot be empty")
}
return
}
其他高级功能
事务处理
GORM 支持事务操作,可以通过 Begin、Commit 和 Rollback 方法来控制事务:
tx := db.Begin()
if err := tx.Create(&student).Error; err != nil {
tx.Rollback()
return err
}
tx.Commit()
关联查询
GORM 支持关联查询(如一对多、多对多关系等)。例如,定义一对多关系:
type Course struct {
ID uint
Name string
Students []Student
}
db.Preload("Students").Find(&courses)
以上示例加载了 Course 表中的所有数据,并预加载了与每个课程相关联的 Students 数据。
分页查询
GORM 也支持分页查询,可以使用 Limit 和 Offset 来实现:
var students []Student
db.Where("Class = ?", 2024).Limit(10).Offset(20).Find(&students)
总结
GORM 是一个强大且灵活的 ORM 库,它使 Go 开发者能够轻松地与关系型数据库进行交互。通过其简洁的 API 和丰富的功能,GORM 让数据库操作变得更加直观和高效。无论是基本的增、删、改、查操作,还是更复杂的事务管理、关联查询等功能,都可以通过 GORM 实现。