644 字
3 分钟
错误处理与调试
GORM 错误处理与调试
Traditional API
每次操作都检查返回的 Error:
result := db.Where("email = ?", email).First(&user)if result.Error != nil { if errors.Is(result.Error, gorm.ErrRecordNotFound) { return ErrUserNotFound } return fmt.Errorf("find user: %w", result.Error)}不要只判断 RowsAffected,也不要忽略 result.Error。
Generics API
Generics API 将错误直接返回:
user, err := gorm.G[User](db).Where("id = ?", id).First(ctx)if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return ErrUserNotFound } return fmt.Errorf("find user: %w", err)}统一使用 errors.Is 判断 GORM 和驱动错误,保留 %w 链路,不要只比较错误字符串。
TranslateError
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{ TranslateError: true,})开启后,部分数据库错误会转换为 GORM 通用错误,例如记录不存在、重复键或外键约束错误。转换可以简化跨数据库判断,但排查问题时仍应记录原始错误上下文。
日志级别
db.Debug().Where("id = ?", id).First(&user)常用级别:
Silent:不输出 SQL。Error:只输出错误。Warn:输出错误和慢 SQL,通常适合生产默认值。Info:输出全部 SQL,适合本地调试或短时间排查。
生产日志建议包含请求 ID、业务操作、耗时、RowsAffected 和错误分类,而不是只打印 SQL 字符串。
记录 SQL 但保护敏感数据
logger.Config{ ParameterizedQueries: true, IgnoreRecordNotFoundError: true, SlowThreshold: 200 * time.Millisecond,}密码、Token、身份证号等敏感字段不要进入 SQL 日志、错误响应或调试输出。开发阶段打印参数也要确认日志不会被上传到公共系统。
DryRun 与执行计划
stmt := db.Session(&gorm.Session{DryRun: true}). Where("email = ?", email). First(&User{}).Statement
fmt.Println(stmt.SQL.String())fmt.Println(stmt.Vars)拿到 SQL 后,在目标数据库中使用 EXPLAIN 检查索引、扫描行数、排序和连接方式。DryRun 不能替代数据库执行计划。
常见错误定位
| 现象 | 先检查 |
|---|---|
record not found | 是否应该把它映射为 404/业务未找到,而不是 500 |
invalid field found | 关联字段、外键、引用字段和标签 |
| 无条件更新/删除被拒绝 | 是否漏写 Where,不要直接全局开启放行 |
| 唯一键冲突 | 业务幂等键、并发竞态和数据库唯一索引 |
| 连接超时 | DSN、网络、连接池、数据库负载和上下文超时 |
| SQL 慢 | 生成 SQL、参数、索引、数据量和执行计划 |
Repository 边界
Repository 可以把底层错误转成领域错误:
var ErrUserNotFound = errors.New("user not found")
func FindUser(ctx context.Context, db *gorm.DB, id uint) (User, error) { var user User if err := db.WithContext(ctx).First(&user, id).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return User{}, ErrUserNotFound } return User{}, fmt.Errorf("find user %d: %w", id, err) } return user, nil}Handler 不需要知道具体数据库错误;Service 负责业务语义,Repository 负责持久化细节。
官方资料
分享文章
生成精美分享图或复制链接,与更多人分享本文。
继续阅读
最后更新于 ,距今已过 77 天
部分内容可能已过时