GORM 在最新版本中引入了 Go Generics 的支持 (>= v1.30.0)。 为日常开发带来了更高的可用性与类型安全,并避免 SQL 污染风险等等。 此外,我们还优化了 Joins 和 Preload 的行为,并新增事务超时处理机制,以帮助开发者更好地应对连接泄漏等常见异常场景。
本次更新在保持原有 API 完全兼容的前提下,较为克制地引入了泛型接口。 你可以在项目中灵活混用传统与泛型两种接口形式,只需在新代码中引入泛型方式,无需担心与现有逻辑或 GORM 插件(如数据加解密、分库分表、读写分离、Tracing 等)之间的兼容性问题。
为了避免误用,我们在泛型版本中有意移除了一些容易引发歧义或并发问题的接口,如 FirstOrCreate、Save 等。 同时,我们也在规划全新的 gorm 命令行工具,未来将提供更强的代码生成、类型安全支持、静态检查 (lint) 能力,进一步减少误用带来的风险。
我们强烈建议你在新项目或重构工作中优先采用泛型版本接口,以获得更好的开发体验、更强的类型保障,以及更易维护的代码结构。
Generic APIs GORM 泛型接口与原接口功能基本不变。 以下是一些最常用操作在泛型接口下的写法:
ctx := context.Background() gorm.G[User](db).Create(ctx, &User{Name: "Alice" }) gorm.G[User](db).CreateInBatches(ctx, users, 10 ) user, err := gorm.G[User](db).Where("name = ?" , "Jinzhu" ).First(ctx) users, err := gorm.G[User](db).Where("age <= ?" , 18 ).Find(ctx) gorm.G[User](db).Where("id = ?" , u.ID).Update(ctx, "age" , 18 ) gorm.G[User](db).Where("id = ?" , u.ID).Updates(ctx, User{Name: "Jinzhu" , Age: 18 }) gorm.G[User](db).Where("id = ?" , u.ID).Delete(ctx)
泛型接口也完整支持 GORM 的高级特性,通过可选参数传入子句(clause)或插件(plugin)扩展,以支持高级特性如执行计划、读写分离等功能,示例如下。
err := gorm.G[Language](DB, clause.OnConflict{DoNothing: true }).Create(ctx, &lang) err := gorm.G[Language](DB, clause.OnConflict{ Columns: []clause.Column{{Name: "id" }}, DoUpdates: clause.Assignments(map [string ]interface {}{"count" : gorm.Expr("GREATEST(count, VALUES(count))" )}), }).Create(ctx, &lang) err := gorm.G[User](DB, hints.New("MAX_EXECUTION_TIME(100)" ), hints.New("USE_INDEX(t1, idx1)" ), ).Find(ctx) err := gorm.G[User](DB, dbresolver.Write).Find(ctx) result := gorm.WithResult() err := gorm.G[User](DB, result).CreateInBatches(ctx, &users, 2 )
Joins / Preload 优化 新版 GORM 泛型接口在关联查询(Joins)与预加载(Preload)等功能进行了增强,支持更灵活的关联方式、更强大的查询表达能力,并显著简化了复杂查询的构造流程。
Joins 接口 : 轻松指定不同的 Join 类型(如 InnerJoin、LeftJoin 等),同时支持基于关联关系自定义 Join 条件,使复杂的跨表查询更加简洁直观。
users, err := gorm.G[User](db).Joins(clause.Has("Company" ), nil ).Find(ctx) user, err = gorm.G[User](db).Joins(clause.LeftJoin.Association("Company" ), func (db gorm.JoinBuilder, joinTable clause.Table, curTable clause.Table) error { db.Where(map [string ]any{"name" : company.Name}) return nil }).Where(map [string ]any{"name" : user.Name}).First(ctx) users, err = gorm.G[User](db).Joins(clause.LeftJoin.AssociationFrom("Company" , gorm.G[Company](DB).Select("Name" )).As("t" ), func (db gorm.JoinBuilder, joinTable clause.Table, curTable clause.Table) error { db.Where("?.name = ?" , joinTable, u.Company.Name) return nil }, ).Find(ctx)
Preload 接口 : 简化自定义查询条件流程,新增了 LimitPerRecord 选项,允许在预加载集合关联时为每条主记录限制相关关联的数量。
users, err := gorm.G[User](db).Preload("Friends" , func (db gorm.PreloadBuilder) error { db.Where("age > ?" , 14 ) return nil }).Where("age > ?" , 18 ).Find(ctx) users, err := gorm.G[User](db).Preload("Friends.Pets" , nil ).Where("age > ?" , 18 ).Find(ctx) users, err = gorm.G[User](db).Preload("Friends" , func (db gorm.PreloadBuilder) error { db.Select("id" , "name" ).Order("age desc" ) return nil }).Preload("Friends.Pets" , func (db gorm.PreloadBuilder) error { db.LimitPerRecord(2 ) return nil }).Find(ctx)
复杂 Raw SQL 支持 GORM 泛型版本依然支持通过 Raw 方法执行原始 SQL 查询,适用于某些非常规或复杂语句的场景:
users, err := gorm.G[User](DB).Raw("SELECT name FROM users WHERE id = ?" , user.ID).Find(ctx)
不过,我们强烈推荐 使用全新的代码生成工具来实现类型安全、可维护性强的原生查询,避免手写 SQL 带来的错误或 SQL 注入等风险。
代码生成工具
go install gorm.io/cli/gorm@latest
你只需将查询接口定义为标准的 Go interface,通过注释使用模板语法标注 SQL,生成器可自动生成类型安全的代码实现:
type Query[T any] interface { GetByID(id int ) (T, error ) FilterWithColumn(column string , value string ) (T, error ) QueryWith(user models.User) (T, error ) Update(user models.User, id int ) error Filter(users []models.User) ([]T, error ) FilterByNameAndAge(name string , age int ) FilterWithTime(start, end time.Time) ([]T, error ) }
gorm gen -i ./examples/example.go -o query
import "your_project/query" company, err := query.Query[Company](db).GetByID(ctx, 10 ) user, err := query.Query[User](db).GetByID(ctx, 10 ) err := query.Query[User](db).FilterByNameAndAge("jinzhu" , 18 ).Delete(ctx) users, err := query.Query[User](db).FilterByNameAndAge("jinzhu" , 18 ).Find(ctx)
Summary 本次发布是 GORM 在泛型支持与全新 gorm 命令工具方向上新的一步。 该系列功能我们已筹划许久,此次终于得以抽出时间,将其初步落地并面向社区发布。
接下来,我们将持续优化和迭代泛型 API 体系、全新 gorm 命令工具,并重构和完善 gorm.io 的官方文档,为开发者带来更清晰、更高效的使用体验。
感谢 GORM 多年来众多使用者与 Sponsors 的支持。 GORM 过去 12 年的发展离不开你们 ❤️