GORM Go 语言 ORM 的 CRUD 操作
FreeGuideOnline
最新
2026-07-08
GORM Go语言ORM的CRUD操作完全指南
什么是GORM?
GORM是Go语言中最受欢迎的ORM库,它通过结构体与数据库表映射,让开发者可以用面向对象的方式操作数据库,而无需编写原始SQL。它支持MySQL、PostgreSQL、SQLite等多种数据库,提供自动迁移、钩子、事务等高级特性,大幅提升开发效率。
环境准备与连接数据库
开始之前,请确保已安装Go语言环境。在项目目录执行以下命令安装GORM及数据库驱动(以MySQL为例):
go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql
连接数据库示例:
import (
"gorm.io/gorm"
"gorm.io/driver/mysql"
)
func main() {
dsn := "user:pass@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")
}
}
定义模型(Model)
GORM使用结构体定义数据库表结构,通过标签指定字段映射、约束等。
type User struct {
ID uint `gorm:"primaryKey"`
Name string `gorm:"size:100;not null"`
Email string `gorm:"uniqueIndex;size:255"`
Age int `gorm:"default:0"`
CreatedAt time.Time
UpdatedAt time.Time
}
执行自动迁移(AutoMigrate)会根据结构体创建或更新表:
db.AutoMigrate(&User{})
创建记录(Create)
单条记录创建
使用Create方法传入结构体指针,GORM会填充主键、时间戳等字段。
user := User{Name: "张三", Email: "zhangsan@example.com", Age: 25}
result := db.Create(&user)
// user.ID 会被赋值为插入后的主键
fmt.Println(user.ID, result.RowsAffected, result.Error)
批量插入
传入切片可一次性插入多条记录,提高性能。
users := []User{
{Name: "李四", Email: "lisi@example.com"},
{Name: "王五", Email: "wangwu@example.com"},
}
db.Create(&users)
指定字段创建
使用Select或Omit控制插入的字段。
db.Select("Name", "Age").Create(&user) // 只插入Name和Age
db.Omit("Email").Create(&user) // 忽略Email字段
创建钩子
GORM提供BeforeCreate、AfterCreate等钩子,可在创建前后执行自定义逻辑。
func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
u.Name = strings.TrimSpace(u.Name)
return
}
查询记录(Read)
查询单条记录
First:按主键升序取第一条Take:无排序取一条Last:按主键降序取最后一条
var user User
// 根据主键查询
db.First(&user, 1) // SELECT * FROM users WHERE id = 1 ORDER BY id LIMIT 1;
// 根据条件
db.First(&user, "email = ?", "zhangsan@example.com")
查询多条记录
使用Find返回所有符合条件的记录。
var users []User
db.Where("age > ?", 18).Find(&users) // 注意:切片需要零值但已分配内存
// 使用指针形式: db.Where("age > ?", 18).Find(&users)
条件查询(Where)
常用的链式条件方法:
db.Where("name = ? AND age >= ?", "张三", 20).Find(&users)
db.Where(&User{Name: "张三", Age: 20}).Find(&users) // 结构体条件,零值字段会被忽略
db.Where(map[string]interface{}{"name": "张三", "age": 20}).Find(&users) // Map条件,零值会包含
db.Not("name = ?", "张三").Find(&users)
db.Or("email = ?", "lisi@example.com").Find(&users)
排序、分页与限制
db.Order("age desc, name").Limit(10).Offset(5).Find(&users)
// Limit指定返回条数,Offset指定跳过条数
选择特定字段
db.Select("name", "age").Find(&users)
关联查询(Preload / Joins)
GORM可以方便地处理关联关系,使用Preload预加载关联数据,或Joins进行连接查询(需要在结构体中定义关联)。
type Order struct {
ID uint
UserID uint
User User
}
db.Preload("User").Find(&orders)
更新记录(Update)
更新单个字段
db.Model(&User{}).Where("id = ?", 1).Update("name", "张三丰")
更新多个字段
使用Updates传入结构体或Map,注意结构体零值字段不会被更新。
// 结构体方式(忽略零值)
db.Model(&user).Updates(User{Name: "新名字", Age: 0}) // Age不会被更新
// Map方式(包含零值)
db.Model(&user).Updates(map[string]interface{}{"name": "新名字", "age": 0})
批量更新
省略Model的主键或结合Where条件可更新多条记录。
db.Model(&User{}).Where("age > ?", 30).Update("status", "active")
使用Save保存整个结构体
Save会更新所有字段,包括零值(根据主键判断是插入还是更新)。
user.Name = "新名字"
db.Save(&user) // 根据user.ID存在则更新全部字段
更新钩子
类似创建,GORM提供BeforeUpdate、AfterUpdate。
删除记录(Delete)
软删除与物理删除
如果模型包含gorm.DeletedAt字段(gorm.Model已包含),则默认启用软删除。删除时只是设置删除时间,实际记录仍留存。
type User struct {
gorm.Model // 包含ID, CreatedAt, UpdatedAt, DeletedAt
Name string
}
// 软删除
db.Delete(&user) // 仅设置DeletedAt
db.Where("id = ?", 1).Delete(&User{}) // 批量软删除
// 物理删除(永久删除)
db.Unscoped().Delete(&user)
根据主键或条件删除
db.Delete(&User{}, 10) // 删除id=10的用户
db.Where("email LIKE ?", "%@test.com").Delete(&User{})
删除钩子
可利用BeforeDelete、AfterDelete执行清理逻辑。
总结与实践建议
- 模型定义清晰,标签使用恰当,可大幅减少手动配置。
- 查询时优先使用占位符避免SQL注入,使用结构体或Map灵活构造条件。
- 更新操作注意零值问题,敏感操作推荐使用Map形式的Updates。
- 生产环境中建议启用PrepareStmt(
&gorm.Config{PrepareStmt: true})以提升性能。 - 结合事务(
db.Transaction)保证数据一致性,尤其是多表关联操作。
通过以上CRUD核心知识,你可以快速上手GORM进行数据库开发,进一步学习可深入研究关联、事务和自定义SQL。