第一个 GORM 应用

理论看再多不如动手写代码。这一章我们从头搭建一个简单的用户管理示例,覆盖 GORM 最常用的功能。

项目结构

myapp/
├── main.go
├── models/
│   └── user.go
└── go.mod

初始化项目

mkdir myapp && cd myapp
go mod init myapp
go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite

用 SQLite 作为示例数据库,省去安装数据库的麻烦。

定义模型

创建 models/user.go

package models

import "gorm.io/gorm"

type User struct {
    gorm.Model
    Name  string `gorm:"size:100;not null"`
    Email string `gorm:"size:100;uniqueIndex"`
    Age   int
}

gorm.Model 是 GORM 内置的结构体,包含四个常用字段:

type Model struct {
    ID        uint           `gorm:"primaryKey"`
    CreatedAt time.Time
    UpdatedAt time.Time
    DeletedAt gorm.DeletedAt `gorm:"index"`
}

嵌入它就自动有了主键、创建时间、更新时间、软删除字段。

连接数据库

创建 main.go

package main

import (
    "fmt"
    "log"
    
    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
    
    "myapp/models"
)

var DB *gorm.DB

func initDB() {
    var err error
    DB, err = gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
    if err != nil {
        log.Fatal("连接数据库失败:", err)
    }
    
    // 自动迁移
    DB.AutoMigrate(&models.User{})
    
    fmt.Println("数据库连接成功")
}

func main() {
    initDB()
    
    // 创建用户
    createUser()
    
    // 查询用户
    queryUser()
    
    // 更新用户
    updateUser()
    
    // 删除用户
    deleteUser()
}

创建记录

func createUser() {
    user := models.User{
        Name:  "张三",
        Email: "zhangsan@example.com",
        Age:   25,
    }
    
    result := DB.Create(&user)
    
    if result.Error != nil {
        log.Println("创建失败:", result.Error)
        return
    }
    
    fmt.Printf("创建成功,ID: %d\n", user.ID)
}

Create 方法返回一个 *gorm.DB 对象,可以获取:

  • result.Error - 错误信息
  • result.RowsAffected - 影响的行数
  • user.ID - 插入后的主键值

批量创建:

users := []models.User{
    {Name: "李四", Email: "lisi@example.com", Age: 28},
    {Name: "王五", Email: "wangwu@example.com", Age: 30},
}
DB.Create(&users)

查询记录

func queryUser() {
    var user models.User
    
    // 根据主键查询
    result := DB.First(&user, 1)
    if result.Error != nil {
        log.Println("查询失败:", result.Error)
        return
    }
    
    fmt.Printf("查询结果: %+v\n", user)
}

常用查询方法:

// 根据主键
DB.First(&user, 1)           // SELECT * FROM users WHERE id = 1
DB.First(&user, "id = ?", 1) // 同上

// 根据条件
DB.Where("name = ?", "张三").First(&user)

// 查询所有
var users []models.User
DB.Find(&users)

// 条件查询
DB.Where("age > ?", 20).Find(&users)

// 排序和限制
DB.Order("age desc").Limit(10).Find(&users)

更新记录

func updateUser() {
    var user models.User
    DB.First(&user, 1)
    
    // 更新单个字段
    DB.Model(&user).Update("age", 26)
    
    // 更新多个字段
    DB.Model(&user).Updates(models.User{
        Name: "张三更新",
        Age:  27,
    })
    
    // 用 map 更新
    DB.Model(&user).Updates(map[string]interface{}{
        "name": "张三",
        "age":  28,
    })
    
    fmt.Println("更新成功")
}

UpdateUpdates 的区别:

  • Update 更新单个字段
  • Updates 更新多个字段,可以用结构体或 map

删除记录

func deleteUser() {
    var user models.User
    DB.First(&user, 1)
    
    // 软删除(因为有 DeletedAt 字段)
    DB.Delete(&user)
    
    fmt.Println("删除成功")
}

因为模型嵌入了 gorm.Model,删除操作是软删除——记录不会真正删除,只是把 deleted_at 设为当前时间。

查询时会自动排除软删除的记录:

DB.Find(&users)  // 不包含软删除的

DB.Unscoped().Find(&users)  // 包含软删除的

真正删除:

DB.Unscoped().Delete(&user)

完整示例

package main

import (
    "fmt"
    "log"
    
    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
    "gorm.io/gorm/logger"
)

type User struct {
    gorm.Model
    Name  string `gorm:"size:100"`
    Email string `gorm:"size:100;uniqueIndex"`
    Age   int
}

func main() {
    // 连接数据库
    db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{
        Logger: logger.Default.LogMode(logger.Info),
    })
    if err != nil {
        log.Fatal(err)
    }
    
    // 迁移
    db.AutoMigrate(&User{})
    
    // 清空表
    db.Exec("DELETE FROM users")
    
    // 创建
    user := User{Name: "张三", Email: "zhangsan@example.com", Age: 25}
    db.Create(&user)
    fmt.Printf("创建: %+v\n", user)
    
    // 查询
    var found User
    db.First(&found, user.ID)
    fmt.Printf("查询: %+v\n", found)
    
    // 更新
    db.Model(&found).Update("age", 26)
    db.First(&found, user.ID)
    fmt.Printf("更新后: %+v\n", found)
    
    // 删除
    db.Delete(&found)
    
    // 验证删除
    var count int64
    db.Model(&User{}).Count(&count)
    fmt.Printf("删除后记录数: %d\n", count)
}

运行:

go run main.go

输出:

创建: {Model:{ID:1 CreatedAt:2024-01-01 10:00:00 UpdatedAt:2024-01-01 10:00:00 DeletedAt:{Time:0001-01-01 00:00:00 Valid:false}} Name:张三 Email:zhangsan@example.com Age:25}
查询: {Model:{ID:1 ...} Name:张三 Email:zhangsan@example.com Age:25}
更新后: {Model:{ID:1 ...} Name:张三 Email:zhangsan@example.com Age:26}
删除后记录数: 0

小结

通过这个示例,我们体验了 GORM 的核心功能:

  • 定义模型(嵌入 gorm.Model
  • 自动迁移(AutoMigrate
  • 创建记录(Create
  • 查询记录(FirstFind
  • 更新记录(UpdateUpdates
  • 删除记录(Delete,软删除)

这些操作覆盖了 80% 的日常使用场景。后面的章节会深入每个功能的细节。