863 字
4 分钟
快速开始

GORM 快速开始#

学习路线#

建议按下面的顺序学习,每完成一个阶段都用 SQLite 跑通示例,再切换到项目实际使用的数据库:

阶段学习内容应达到的结果
入门连接数据库、模型、迁移、Create/First/Find能完成单表增删改查
查询Where、Select、Order、分页、Scopes能写出可维护的列表查询
关系Belongs To、Has Many、Many2Many、Preload能处理多表读写
一致性事务、锁、错误处理、上下文能保证关键业务的原子性
工程化配置注入、Repository、日志、连接池能集成到 Gin 项目
优化批量操作、索引、DryRun、Explain、N+1 排查能定位并改善慢查询

配套笔记:

安装依赖#

下面的模板使用 SQLite,不需要先启动数据库服务:

Terminal window
go mod init example.com/gorm-demo
go get gorm.io/gorm
go get gorm.io/driver/sqlite
go run .

生产项目按实际数据源安装驱动,例如 MySQL:

Terminal window
go get gorm.io/driver/mysql

可运行模板#

将下面内容保存为 main.go,即可创建一个 SQLite 文件数据库、自动建表、写入并查询一条用户记录。

package main
import (
"context"
"errors"
"fmt"
"log"
"os"
"time"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
type User struct {
ID uint `gorm:"primaryKey"`
Name string
Email string `gorm:"uniqueIndex;not null"`
Age int
CreatedAt time.Time
UpdatedAt time.Time
}
func main() {
newLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags),
logger.Config{
SlowThreshold: time.Second,
LogLevel: logger.Warn,
IgnoreRecordNotFoundError: true,
ParameterizedQueries: true,
Colorful: false,
},
)
db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{
Logger: newLogger,
})
if err != nil {
log.Fatalf("open database: %v", err)
}
// AutoMigrate 适合学习和开发阶段;生产环境请看《迁移与初始化》。
if err := db.AutoMigrate(&User{}); err != nil {
log.Fatalf("migrate database: %v", err)
}
// *gorm.DB 底层使用 database/sql,可在这里配置连接池并检查连接。
sqlDB, err := db.DB()
if err != nil {
log.Fatalf("get sql.DB: %v", err)
}
defer sqlDB.Close()
sqlDB.SetMaxIdleConns(10)
sqlDB.SetMaxOpenConns(50)
sqlDB.SetConnMaxLifetime(time.Hour)
if err := sqlDB.PingContext(context.Background()); err != nil {
log.Fatalf("ping database: %v", err)
}
ctx := context.Background()
user := User{Name: "Alice", Email: "alice@example.com", Age: 18}
if err := db.WithContext(ctx).Create(&user).Error; err != nil {
log.Fatalf("create user: %v", err)
}
var found User
if err := db.WithContext(ctx).First(&found, user.ID).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
log.Fatal("user not found")
}
log.Fatalf("find user: %v", err)
}
fmt.Printf("user: %+v\n", found)
}

切换到 MySQL#

将导入和连接部分替换为:

import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
dsn := "user:password@tcp(127.0.0.1:3306)/demo?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})

charset=utf8mb4 用于完整支持 UTF-8,parseTime=True 用于正确解析 time.Time。不要把真实密码硬编码到源码,改用环境变量或配置文件,详见数据源配置。

两种 API 风格#

传统 API 返回 *gorm.DB,错误从 .Error 读取:

var user User
result := db.Where("email = ?", "alice@example.com").First(&user)
if result.Error != nil {
// 处理错误
}

Generics API 从 GORM v1.30.0 起可用,错误直接由操作返回,并且查询结果有明确类型:

user, err := gorm.G[User](db).
Where("email = ?", "alice@example.com").
First(ctx)
if err != nil {
// 处理错误
}

学习时建议先掌握传统 API,因为现有项目中仍很常见;新代码可根据团队版本和偏好选择 Generics API。两种风格的完整对照见CRUD 查询。

第一个练习#

在模板基础上完成:

  • 增加 Status 字段并迁移。
  • 查询年龄大于 18 岁的用户并按创建时间倒序排列。
  • 编写分页函数,返回用户列表和总数。
  • 将创建用户和创建用户资料放进一个事务。
  • 打开 db.Debug(),观察每个操作生成的 SQL。

官方资料#

快速开始
https://shirone.mysqil.com/posts/gorm/快速开始/
作者
HikariTish
发布于
2026-07-30
许可协议
CC BY-NC-SA 4.0

分享文章

生成精美分享图或复制链接,与更多人分享本文。

继续阅读

沿着主题读

基于共同的标签与分类

换条路线

从其他文章中稳定抽取