GORM 详细教程
GORM 是 Go 语言中最流行的 ORM (对象关系映射) 库之一,提供了强大的数据库操作功能。本教程将详细介绍 GORM 的使用方法。
目录
- 安装与配置
- 模型定义
- 基本CRUD操作
- 查询操作
- 关联关系
- 事务处理
- 钩子方法
- 高级特性
- 性能优化
安装与配置
安装
go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite # 根据使用的数据库选择对应的驱动
连接数据库
import (
"gorm.io/gorm"
"gorm.io/driver/mysql"
)
func main() {
// MySQL 连接示例
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")
}
// SQLite 连接示例
// db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{})
}
配置
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
SkipDefaultTransaction: true, // 禁用默认事务
NamingStrategy: schema.NamingStrategy{
TablePrefix: "t_", // 表名前缀
SingularTable: true, // 使用单数表名
},
Logger: logger.Default.LogMode(logger.Info), // 日志配置
})
模型定义
基本模型
type User struct {
gorm.Model // 内嵌包含ID, CreatedAt, UpdatedAt, DeletedAt字段
Name string
Age int
Birthday time.Time
}
字段标签
type User struct {
gorm.Model
Name string `gorm:"type:varchar(100);uniqueIndex"`
Age int `gorm:"default:18"`
Birthday time.Time
Active bool `gorm:"default:true"`
Email string `gorm:"unique;not null"`
}
表名设置
// 实现TableName方法自定义表名
func (User) TableName() string {
return "profiles"
}
基本CRUD操作
创建记录
// 创建单条记录
user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}
result := db.Create(&user)
// 批量插入
users := []User{
{Name: "Alice", Age: 22},
{Name: "Bob", Age: 25},
}
db.Create(&users)
// 选择字段创建
db.Select("Name", "Age").Create(&user)
// 忽略字段创建
db.Omit("Age").Create(&user)
查询记录
// 查询单条记录
var user User
db.First(&user, 1) // 查询id=1的记录
db.First(&user, "name = ?", "Jinzhu") // 条件查询
// 查询多条记录
var users []User
db.Find(&users, "age > ?", 20)
// 获取第一条记录(按主键排序)
db.First(&user)
// 获取最后一条记录
db.Last(&user)
更新记录
// 更新单个字段
db.Model(&user).Update("name", "hello")
// 更新多个字段
db.Model(&user).Updates(User{Name: "hello", Age: 18})
// 更新选定字段
db.Model(&user).Select("name").Updates(map[string]interface{}{"name": "hello", "age": 18})
// 批量更新
db.Model(User{}).Where("age > ?", 20).Updates(map[string]interface{}{"age": gorm.Expr("age + ?", 1)})
删除记录
// 删除记录
db.Delete(&user)
// 带条件删除
db.Where("name = ?", "Jinzhu").Delete(&user)
// 批量删除
db.Where("age < ?", 20).Delete(&User{})
// 软删除(如果模型有DeletedAt字段)
db.Delete(&user, 1)
查询操作
条件查询
// 字符串条件
db.Where("name = ?", "jinzhu").First(&user)
// 结构体/Map条件
db.Where(&User{Name: "jinzhu", Age: 20}).First(&user)
db.Where(map[string]interface{}{"name": "jinzhu", "age": 20}).Find(&users)
// 主键查询
db.First(&user, 10) // SELECT * FROM users WHERE id = 10;
高级查询
// Not条件
db.Not("name = ?", "jinzhu").First(&user)
// Or条件
db.Where("name = ?", "jinzhu").Or("name = ?", "alice").Find(&users)
// 排序
db.Order("age desc, name").Find(&users)
// Limit & Offset
db.Limit(10).Offset(5).Find(&users)
// 选择字段
db.Select("name", "age").Find(&users)
// 分组
db.Model(&User{}).Select("name, sum(age) as total").Group("name").Find(&result)
原生SQL
// 原生SQL查询
db.Raw("SELECT id, name, age FROM users WHERE name = ?", "jinzhu").Scan(&result)
// Exec执行原生SQL
db.Exec("DROP TABLE users")
关联关系
一对一
type User struct {
gorm.Model
Profile Profile
}
type Profile struct {
gorm.Model
UserID uint
Name string
}
// 自动创建/迁移表
db.AutoMigrate(&User{}, &Profile{})
// 创建关联
user := User{
Profile: Profile{Name: "Jinzhu"},
}
db.Create(&user)
// 预加载关联
db.Preload("Profile").First(&user)
一对多
type User struct {
gorm.Model
CreditCards []CreditCard
}
type CreditCard struct {
gorm.Model
Number string
UserID uint
}
// 查询
var user User
db.Preload("CreditCards").First(&user, 1)
// 添加关联
db.Model(&user).Association("CreditCards").Append([]CreditCard{
{Number: "123456"},
{Number: "789012"},
})
多对多
type User struct {
gorm.Model
Languages []Language `gorm:"many2many:user_languages;"`
}
type Language struct {
gorm.Model
Name string
}
// 查询
var user User
db.Preload("Languages").First(&user, 1)
// 添加关联
var languages []Language
db.Find(&languages, "name IN ?", []string{"zh", "en"})
db.Model(&user).Association("Languages").Append(languages)
事务处理
自动事务
if err := db.Transaction(func(tx *gorm.DB) error {
if err := tx.Create(&User{Name: "Gorm"}).Error; err != nil {
return err
}
if err := tx.Create(&User{Name: "Gorm2"}).Error; err != nil {
return err
}
return nil
}); err != nil {
// 处理错误
}
手动事务
// 开始事务
tx := db.Begin()
if err := tx.Create(&User{Name: "Gorm"}).Error; err != nil {
tx.Rollback()
return
}
if err := tx.Create(&User{Name: "Gorm2"}).Error; err != nil {
tx.Rollback()
return
}
// 提交事务
tx.Commit()
钩子方法
GORM 提供了模型生命周期钩子:
type User struct {
gorm.Model
Name string
}
// 创建前钩子
func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
u.Name = "Mr." + u.Name
return
}
// 更新前钩子
func (u *User) BeforeUpdate(tx *gorm.DB) (err error) {
if u.Age < 0 {
return errors.New("invalid age")
}
return
}
// 查询后钩子
func (u *User) AfterFind(tx *gorm.DB) (err error) {
fmt.Println("found user:", u.Name)
return
}
高级特性
复合主键
type Product struct {
ID string `gorm:"primaryKey"`
LanguageCode string `gorm:"primaryKey"`
Code string
Name string
}
自定义数据类型
import "database/sql/driver"
type JSON json.RawMessage
func (j *JSON) Scan(value interface{}) error {
// 实现Scan方法
}
func (j JSON) Value() (driver.Value, error) {
// 实现Value方法
}
type User struct {
gorm.Model
Settings JSON
}
连接池配置
sqlDB, err := db.DB()
// SetMaxIdleConns 设置空闲连接池中连接的最大数量
sqlDB.SetMaxIdleConns(10)
// SetMaxOpenConns 设置打开数据库连接的最大数量
sqlDB.SetMaxOpenConns(100)
// SetConnMaxLifetime 设置了连接可复用的最大时间
sqlDB.SetConnMaxLifetime(time.Hour)
性能优化
- 禁用默认事务:对于简单的单次查询,可以禁用默认事务
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{ SkipDefaultTransaction: true, })
- 批量操作:使用批量插入、更新和删除
- 预加载:使用
Preload
避免N+1查询问题 - 选择字段:只查询需要的字段
db.Select("name", "age").Find(&users)
- 使用缓存:对频繁查询但不常变化的数据使用缓存
- 索引优化:为常用查询条件添加索引
总结
GORM 提供了强大而灵活的 ORM 功能,可以大大简化 Go 语言中的数据库操作。通过本教程,你应该已经掌握了 GORM 的核心功能,包括模型定义、CRUD操作、关联关系、事务处理等高级特性。
更多详细内容可以参考 GORM 官方文档。