3、数据库连接与ORM:配置MySQL连接、使用GORM进行CRUD操作、数据库迁移
在Go项目业务接口落地过程中,数据库是持久化层核心。本章围绕MySQL连接配置、GORM对象关系映射以及数据库迁移三个关键环节展开,确保数据层具备可维护、可测试、可迁移的生产级能力。
3.1 MySQL连接配置
生产环境推荐使用gorm.io/driver/mysql驱动,配合连接池参数控制资源消耗。以下为典型配置结构:
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
"time"
)
type DBConfig struct {
DSN string // 数据源名称
MaxIdleConns int // 最大空闲连接数
MaxOpenConns int // 最大打开连接数
ConnMaxLifetime time.Duration // 连接最大存活时间
}
func NewGORM(cfg DBConfig) (*gorm.DB, error) {
db, err := gorm.Open(mysql.Open(cfg.DSN), &gorm.Config{
SkipDefaultTransaction: true, // 提升单行写入性能
PrepareStmt: true, // 预编译缓存
})
if err != nil {
return nil, err
}
sqlDB, _ := db.DB()
sqlDB.SetMaxIdleConns(cfg.MaxIdleConns)
sqlDB.SetMaxOpenConns(cfg.MaxOpenConns)
sqlDB.SetConnMaxLifetime(cfg.ConnMaxLifetime)
return db, nil
}
DSN格式示例:
user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local。务必开启parseTime=True以自动处理时间类型。
3.2 使用GORM进行CRUD操作
GORM通过结构体标签映射表字段,支持链式调用与钩子函数。以下为完整CRUD示例:
// 定义模型
type User struct {
ID uint `gorm:"primaryKey;autoIncrement"`
Name string `gorm:"type:varchar(100);not null;index:idx_name"`
Email string `gorm:"type:varchar(255);uniqueIndex"`
Age int `gorm:"default:0"`
CreatedAt time.Time
UpdatedAt time.Time
}
// Create
func CreateUser(db *gorm.DB, user *User) error {
return db.Create(user).Error
}
// Read
func GetUserByID(db *gorm.DB, id uint) (*User, error) {
var user User
err := db.First(&user, id).Error
return &user, err
}
// Update
func UpdateUserEmail(db *gorm.DB, id uint, email string) error {
return db.Model(&User{}).Where("id = ?", id).Update("email", email).Error
}
// Delete
func DeleteUser(db *gorm.DB, id uint) error {
return db.Delete(&User{}, id).Error
}
| 操作 | GORM方法 | 注意事项 |
|---|---|---|
| 创建 | Create |
批量插入使用Create(&users)传入切片 |
| 查询单条 | First / Take |
First按主键排序,Take不排序 |
| 条件查询 | Where / Find |
支持map、struct、原生SQL |
| 更新 | Save / Update |
Save全字段更新,Update指定列 |
| 删除 | Delete |
默认软删除需在模型包含DeletedAt字段 |
常见陷阱:GORM的
First方法在记录不存在时返回ErrRecordNotFound,业务层应显式处理该错误,避免空指针。
3.3 数据库迁移
GORM内置AutoMigrate用于自动建表、增列、改索引,但不处理列类型变更或数据迁移。生产环境建议结合gormigrate或手工SQL实现版本化迁移。
// 自动迁移(开发/测试环境常用)
func AutoMigrate(db *gorm.DB) error {
return db.AutoMigrate(
&User{},
&Order{},
&Product{},
)
}
// 版本化迁移示例(使用 gormigrate)
import "github.com/go-gormigrate/gormigrate/v2"
func Migrate(db *gorm.DB) error {
m := gormigrate.New(db, gormigrate.DefaultOptions, []*gormigrate.Migration{
{
ID: "2024010101",
Migrate: func(tx *gorm.DB) error {
return tx.AutoMigrate(&User{})
},
Rollback: func(tx *gorm.DB) error {
return tx.Migrator().DropTable("users")
},
},
{
ID: "2024010102",
Migrate: func(tx *gorm.DB) error {
return tx.AutoMigrate(&Order{})
},
Rollback: func(tx *gorm.DB) error {
return tx.Migrator().DropTable("orders")
},
},
})
return m.Migrate()
}
迁移策略对比:
- AutoMigrate:适合快速原型、单开发者项目;无法回滚,列删除需手动。
- gormigrate:适合团队协作、CI/CD流水线;支持版本号、回滚、幂等执行。
- 手工SQL + 迁移工具:适合大型项目、DBA审核;推荐
golang-migrate/migrate。
3.4 连接池参数调优建议
| 参数 | 推荐值 | 说明 |
|---|---|---|
MaxIdleConns |
10 | 避免频繁创建销毁连接,降低延迟 |
MaxOpenConns |
100 | 根据数据库最大连接数设置,防止过载 |
ConnMaxLifetime |
5分钟 | 防止数据库侧主动断开导致连接失效 |
CI/CD集成提示:在流水线中执行数据库迁移前,应使用
gormigrate的Migrate()幂等方法,并配合--dry-run参数预览变更。迁移脚本应纳入版本控制,与业务代码一同发布。