863 字
4 分钟
快速开始
GORM 快速开始
学习路线
建议按下面的顺序学习,每完成一个阶段都用 SQLite 跑通示例,再切换到项目实际使用的数据库:
| 阶段 | 学习内容 | 应达到的结果 |
|---|---|---|
| 入门 | 连接数据库、模型、迁移、Create/First/Find | 能完成单表增删改查 |
| 查询 | Where、Select、Order、分页、Scopes | 能写出可维护的列表查询 |
| 关系 | Belongs To、Has Many、Many2Many、Preload | 能处理多表读写 |
| 一致性 | 事务、锁、错误处理、上下文 | 能保证关键业务的原子性 |
| 工程化 | 配置注入、Repository、日志、连接池 | 能集成到 Gin 项目 |
| 优化 | 批量操作、索引、DryRun、Explain、N+1 排查 | 能定位并改善慢查询 |
配套笔记:
安装依赖
下面的模板使用 SQLite,不需要先启动数据库服务:
go mod init example.com/gorm-demogo get gorm.io/gormgo get gorm.io/driver/sqlitego run .生产项目按实际数据源安装驱动,例如 MySQL:
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 Userresult := 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。
官方资料
分享文章
生成精美分享图或复制链接,与更多人分享本文。
继续阅读
换条路线
从其他文章中稳定抽取
最后更新于 ,距今已过 77 天
部分内容可能已过时