2. GORM 快速入门:安装、配置、模型与 CRUD

本章是 GORM 的实战起点。你将学会如何安装 GORM、配置数据库连接、定义模型、使用 AutoMigrate 自动建表,并完成最核心的 CRUD 操作。掌握这些基础后,后续的迁移与性能剖析才有坚实的操作基础。

2.1 GORM 安装与数据库驱动

GORM 采用模块化驱动设计,安装时需同时选择对应的数据库驱动。以下为常用驱动组合:

数据库 驱动包路径 导入别名
MySQL gorm.io/driver/mysql "gorm.io/driver/mysql"
PostgreSQL gorm.io/driver/postgres "gorm.io/driver/postgres"
SQLite gorm.io/driver/sqlite "gorm.io/driver/sqlite"
SQL Server gorm.io/driver/sqlserver "gorm.io/driver/sqlserver"
安装命令(以 MySQL 为例):
go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql

2.2 数据库连接配置

GORM 通过 gorm.Open 建立连接,支持 DSN 字符串与配置结构体两种方式。推荐使用配置结构体,便于后期扩展连接池参数。

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

// DSN 格式:user:password@tcp(host:port)/dbname?charset=utf8mb4&parseTime=True&loc=Local
dsn := "root:password@tcp(127.0.0.1:3306)/testdb?charset=utf8mb4&parseTime=True&loc=Local"

db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
  SkipDefaultTransaction: true, // 关闭默认事务提升性能
  PrepareStmt:            true, // 缓存预编译语句
})
if err != nil {
  panic("数据库连接失败: " + err.Error())
}

// 获取底层 sql.DB 实例,配置连接池
sqlDB, _ := db.DB()
sqlDB.SetMaxIdleConns(10)
sqlDB.SetMaxOpenConns(100)
sqlDB.SetConnMaxLifetime(time.Hour)
连接池参数建议: 生产环境 SetMaxOpenConns 建议不超过数据库最大连接数的 80%,SetConnMaxLifetime 建议小于数据库的 wait_timeout(通常 300s)。

2.3 模型定义基础

GORM 模型是 Go 结构体,通过标签(Tag)映射数据库表字段。推荐内嵌 gorm.Model 自动获得 ID、CreatedAt、UpdatedAt、DeletedAt 四个通用字段。

type User struct {
  gorm.Model                // 内嵌:ID, CreatedAt, UpdatedAt, DeletedAt
  Name       string         `gorm:"type:varchar(100);not null;comment:用户名"`
  Email      string         `gorm:"type:varchar(200);uniqueIndex;comment:邮箱"`
  Age        uint8          `gorm:"default:18;comment:年龄"`
  Birthday   *time.Time     `gorm:"comment:生日"`
  MemberNumber sql.NullString `gorm:"uniqueIndex;comment:会员号"`
  Status     int            `gorm:"default:1;comment:状态 1-启用 0-禁用"`
}
标签 作用 示例
column 指定列名 column:user_name
type 列数据类型 type:varchar(100)
size 列大小/长度 size:256
primaryKey 主键 primaryKey
uniqueIndex 唯一索引 uniqueIndex
default 默认值 default:18
not null 非空约束 not null
comment 字段注释 comment:用户名

2.4 AutoMigrate 自动迁移

AutoMigrate 会根据模型结构体自动创建或更新数据库表,仅会新增列、修改列类型、增加索引,不会删除列或索引,适合开发与测试环境快速迭代。

// 自动迁移:创建或更新表结构
err := db.AutoMigrate(&User{}, &Product{}, &Order{})
if err != nil {
  panic("自动迁移失败: " + err.Error())
}
生产环境注意: AutoMigrate 不会处理列重命名、列删除、数据迁移等破坏性变更。生产环境应使用版本化迁移工具(如 golang-migrate)或 GORM 的 Migrator 接口手动控制。
AutoMigrate 执行流程 模型定义 对比现有表 生成 DDL 执行 SQL AutoMigrate 行为规则 ✅ 新增列(ALTER TABLE ADD COLUMN) ✅ 修改列类型(ALTER TABLE MODIFY COLUMN) ✅ 新增索引(CREATE INDEX) ❌ 不会删除列或索引

2.5 CRUD 基本操作

GORM 的 CRUD 方法链式调用,语义清晰。以下为最常用的操作模式:

2.5.1 创建(Create)

// 单条创建
user := User{Name: "张三", Email: "zhangsan@example.com", Age: 25}
result := db.Create(&user)
fmt.Println("新记录 ID:", user.ID, "影响行数:", result.RowsAffected)

// 批量创建
users := []User{
  {Name: "李四", Email: "lisi@example.com"},
  {Name: "王五", Email: "wangwu@example.com"},
}
db.Create(&users)

2.5.2 查询(Read)

// 查询单条
var user User
db.First(&user, 1)                    // 按主键查询
db.First(&user, "email = ?", "zhangsan@example.com") // 条件查询

// 查询多条
var users []User
db.Where("age > ?", 20).Find(&users)  // 条件过滤
db.Limit(10).Offset(0).Find(&users)   // 分页查询

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

2.5.3 更新(Update)

// 更新单个字段
db.Model(&User{}).Where("id = ?", 1).Update("name", "张三丰")

// 更新多个字段
db.Model(&user).Updates(User{Name: "张三丰", Age: 30}) // 零值字段不会被更新
db.Model(&user).Updates(map[string]interface{}{"name": "张三丰", "age": 30}) // 零值也会更新

2.5.4 删除(Delete)

// 软删除(模型内嵌 gorm.Model 时默认软删除)
db.Delete(&User{}, 1)

// 物理删除
db.Unscoped().Delete(&User{}, 1)
GORM CRUD 操作链路 GORM DB 实例 Create Read Update Delete 💡 所有操作均支持链式调用:db.Where().Order().Limit().Find()
CRUD 避坑指南:
  • Updates 零值问题: 结构体更新时零值字段不会被更新,如需更新零值请使用 map。
  • First 与 Take 区别: First 按主键排序取第一条,Take 不排序直接取一条。
  • 软删除查询: 默认查询会过滤 deleted_at IS NULL 的记录,使用 Unscoped() 可查询全部。

2.6 完整示例:用户表 CRUD

package main

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

type User struct {
  gorm.Model
  Name  string `gorm:"type:varchar(100);not null"`
  Email string `gorm:"type:varchar(200);uniqueIndex;not null"`
  Age   uint8  `gorm:"default:18"`
}

func main() {
  dsn := "root: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("连接失败")
  }

  // 自动迁移
  db.AutoMigrate(&User{})

  // 创建
  db.Create(&User{Name: "张三", Email: "zs@example.com", Age: 25})

  // 查询
  var user User
  db.First(&user, "email = ?", "zs@example.com")
  fmt.Printf("查询结果: %+v\n", user)

  // 更新
  db.Model(&user).Update("age", 26)

  // 删除
  db.Delete(&user)
}

通过以上步骤,你已经完成了 GORM 的安装、数据库连接、模型定义、自动迁移以及完整的 CRUD 操作。这些基础能力将贯穿后续所有章节,请务必动手实践每个代码片段。