Go数据库操作异常处理
Go 数据库操作异常处理插入操作
第一种写法 err := db.Model(&XXX{}).Create(order).Error if err != nil { logs.CtxError(ctx, "Create XXX failed, err:%v", err.Error()) return err }
第二种写法 db := db.Model(&XXX{}).Create(order) if db.Error != nil { logs.CtxError(ctx, "Create XXX failed, err:%v", db.Error) return db.Error }
上述两种写法说明:
两种写法都没啥问题,第一种写法, 如果只插入一条数据,可以使用第一种写法简单;第二种写法可以拿到执行的 *DB ,方便后续的 DB 操作更新操作db := db.Model(&Voucher{}).Where(whereMap).Updates(updateMap) if db == nil { return 0, errors.New(fmt.Sprintf("UpdateVoucherWithState failed, db is null, jrUid:%s, voucherNo:%s", jrUid, voucherNo)) } err := db.Error if err != nil { logs.CtxError(ctx, "UpdateXXX failed err:%v", err) } if db.RowsAffected != 1{ logs.CtxWarn(ctx, "UpdateXXX failed RowsAffected:%v", db.RowsAffected) // TODO 根据业务自身特性单独处理 }
说明:
update 方法将返回执行完之后的 *DB, 需要通过指针对象才能获取正确的 RowAffected 。事务处理tx, txErr = model.BeginTransactionNotShard(ctx) if txErr != nil { logs.CtxError(ctx, "db BeginTransaction err: %v", txErr) return constant.GenRetCode(constant.DBError, txErr.Error()) } defer func() { if err := recover(); err != nil { logs.CtxError(ctx, "panic:%+v", err) tx.Rollback(ctx, tx) } else if err != nil { // logs.CtxError tx.Rollback() } }() if err := tx.Error; err != nil { return err } if err:= tx.Create(&XXX).Error; err != nil { return err } return tx.Commit().Error
事务的提交也可能会有 error , 要判断是否正确 commit
需要判断 tx.Error ,因为事务的提交可能会有 error 查询的异常处理if err := db.Where("name = ?", "jianzhu").First(&user).Error; err != nil { if errors.Is(err, gorm.ErrRecordFound) { // TODO 业务处理查询不到数据的情况 } if err != nil { // do something ... } }
其实要注意的是,没查询到结果,也会返回一个 Error
gorm 的ErrRecordNotFound 也好理解,假设根据身份证号查询公民信息,如果是一个无效的身份证ID,那必然无法查询到结果, 其实就是查询不到结果,会返回一个错误。
当然 GORM 提供了一个处理 RecordNotFound 错误的快捷方式,如果发生了多个错误,它将检查每个错误,如果它们中的任何一个是RecordNotFound 错误。 //检查是否返回 RecordNotFound 错误 db.Where("name = ?", "hello world").First(&user).RecordNotFound() if db.Model(&user).Related(&credit_card).RecordNotFound() { // 数据没有找到 } if err := db.Where("name = ?", "jinzhu").First(&user).Error; gorm.IsRecordNotFoundError(err) { // 数据没有找到 } WX搜索:程序员财富自由之路
当一个程序中使用两个不同的数据库时, 重写方法DefaultTableNameHandler()会影响到两个数据库中的表名。 其中一个数据库需要设置表前缀时,访问另一个数据库的表也可能会被加上前缀。 因为是包级别的方法,整个代码里只能设置一次值。 参考资料https://gorm.io/docs/transactions.html http://blog.vikazhou.com/2020/02/09/GORM-Problem-Analyze/ https://www.topgoer.com/%E6%95%B0%E6%8D%AE%E5%BA%93%E6%93%8D%E4%BD%9C/gorm/%E6%95%99%E7%A8%8B/%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86.html