使用GORM无法捕获ErrRecordNotFound错误,无法执行创建操作
问题解决:GORM未捕获ErrRecordNotFound导致程序终止
问题代码
err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where("description = ?", item.Description).First(&exist).Error if errors.Is(err, gorm.ErrRecordNotFound) { err = r.db.Create(&entity.Item{ Name: item.Name, Description: item.Description, Quantity: item.Quantity, OrderID: order.ID, }).Error if err != nil { return err } }
日志信息
record not found [5.093ms] [rows:0] SELECT * FROM "items" WHERE description = 'iPhone' ORDER BY "items"."id" LIMIT 1 FOR UPDATE
问题分析
程序直接终止且未执行创建逻辑,核心原因有两个:
- 未处理
ErrRecordNotFound之外的其他错误,若查询时出现数据库连接、权限等异常,代码会跳过分支直接执行后续逻辑,引发未捕获错误导致程序终止。 - 查询用事务实例
tx,但创建用非事务实例r.db,跨事务操作可能引发上下文异常。 - 部分GORM版本中,
errors.Is可能无法正确匹配包装后的ErrRecordNotFound错误。
修复方案
修复后代码
err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where("description = ?", item.Description).First(&exist).Error if err != nil { // 优先判断记录不存在的情况,支持直接比较或errors.Is if err == gorm.ErrRecordNotFound || errors.Is(err, gorm.ErrRecordNotFound) { // 使用事务实例执行创建,保持事务一致性 err = tx.Create(&entity.Item{ Name: item.Name, Description: item.Description, Quantity: item.Quantity, OrderID: order.ID, }).Error if err != nil { return err } } else { // 直接返回其他查询错误,避免程序异常终止 return err } } // 此处可添加查询到记录后的处理逻辑
关键修复点
- 增加全局错误判断:先捕获所有查询错误,再分支处理不同类型,避免遗漏异常。
- 统一事务上下文:创建操作改用
tx.Create,确保所有操作在同一个事务中执行。 - 兼容错误匹配:同时支持直接比较和
errors.Is,适配不同GORM版本的错误包装逻辑。
内容的提问来源于stack exchange,提问作者krtksr
相关产品推荐
相关产品推荐

