Gorm中的First()、Create()、Update()、Delete()的错误处理
一. First()
result := tx.Model(&models.Attachment{}).Where("home = ? AND home_id = ?", attachment.Home, attachment.HomeID).First(&existingAttachment)
如果没有查询到数据,result.Error的值是什么?
在使用 GORM(Go 的 ORM 框架)进行数据库操作时,result.Error 的值取决于查询的执行情况。
如果查询没有找到任何数据,result.Error 的值通常是 gorm.ErrRecordNotFound。
解释:
1.First 方法:First 方法会尝试获取查询结果的第一条记录。如果没有找到任何匹配的记录,GORM 会返回一个错误,通常是 gorm.ErrRecordNotFound。
2.result.Error:result.Error 是 GORM 的 Result 结构体中的一个字段,用于存储查询或操作过程中发生的错误。如果没有错误,它的值为 nil;如果有错误,它会包含具体的错误信息。
示例代码:
if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
// 没有找到数据
fmt.Println("No record found")
} else {
// 其他错误
fmt.Println("Error occurred:", result.Error)
}
} else {
// 查询成功,数据存储在 existingAttachment 中
fmt.Println("Record found:", existingAttachment)
}
注意事项:
- 如果你希望在没有找到数据时不返回错误,可以使用 Take 方法代替 First。Take 方法在没有找到数据时不会返回错误,而是将目标变量设置为默认值。
- 如果你使用的是 GORM v2 或更高版本,gorm.ErrRecordNotFound 是一个常量错误,可以通过 errors.Is 来判断是否是“未找到记录”的错误。
二. Create()
// 向api表中添加api相关信息
err := tx.Model(models.Api{}).Create(&api).Error
if err != nil {
tx.Rollback() // 回滚事务
return fmt.Errorf("CreateApiRep -> 向api表中添加api相关信息失败 -> %s", err)
}
如果插入数据失败,err的值是什么?
在使用 GORM 的 Create 方法插入数据时,如果插入操作失败,err 的值将是一个具体的错误对象,其内容取决于失败的原因。这些错误通常是由数据库操作或约束违反引起的。以下是一些常见的错误类型及其可能的值:
1. 数据库约束违反
如果插入的数据违反了数据库的约束(如主键冲突、唯一约束冲突、外键约束等),err 的值通常是一个 *pq.Error(PostgreSQL)或 *mysql.MySQLError(MySQL)对象,具体取决于你使用的数据库驱动。
示例错误:
- 主键冲突(MySQL):
Error 1062: Duplicate entry '1' for key 'PRIMARY'
- 唯一约束冲突(MySQL):
Error 1062: Duplicate entry 'example' for key 'unique_key_name'
- 外键约束冲突(MySQL):
Error 1452: Cannot add or update a child row: a foreign key constraint fails
示例错误(PostgreSQL):
- 主键冲突:
pq: duplicate key value violates unique constraint "pkey_name"
- 唯一约束冲突:
pq: duplicate key value violates unique constraint "unique_constraint_name"
2. 数据类型不匹配
如果插入的数据类型与数据库表定义不匹配(如字符串长度超出限制、字段类型不匹配等),err 的值通常是一个语法错误或类型错误。
示例错误(MySQL):
Error 1265: Data truncated for column 'column_name' at row 1
3. 数据库连接问题
如果数据库连接失败或超时,err 的值可能是一个连接错误。
示例错误:
dial tcp 127.0.0.1:3306: connect: connection refused
4. 其他错误
其他可能的错误包括:
- SQL 语法错误:
Error 1064: You have an error in your SQL syntax
- 事务回滚错误:
transaction is already rolled back
如何处理这些错误
在实际开发中,你可以根据错误类型进行相应的处理。以下是一些常见的处理方式:
示例代码:
err := tx.Model(models.Api{}).Create(&api).Error
if err != nil {
tx.Rollback() // 回滚事务
if gorm.IsRecordNotFoundError(err) {
return fmt.Errorf("CreateApiRep -> 插入数据失败:记录未找到")
} else if strings.Contains(err.Error(), "Duplicate entry") {
return fmt.Errorf("CreateApiRep -> 插入数据失败:唯一约束冲突")
} else {
return fmt.Errorf("CreateApiRep -> 插入数据失败 -> %s", err)
}
}
总结
- err 的值取决于插入操作失败的具体原因。
- 常见的错误类型包括数据库约束违反、数据类型不匹配、连接问题等。
- 你可以通过检查错误消息或使用 GORM 提供的工具(如 gorm.IsRecordNotFoundError)来处理这些错误。
三. Update()
// 更新 api_group 表中的 group_id
resag := tx.Model(&models.ApiDictItemGroup{}).Where("api_id = ?", api.ID).Update("group_id", groupId)
if resag.Error != nil {
tx.Rollback() // 回滚事务
return fmt.Errorf("UpdateApiRep -> 更新 api_group 表中的 group_id失败 -> %s", resag.Error)
}
当更新的数据与原数据相同时,resag.RowsAffected的值是什么?
在 GORM 中,Update 方法的 RowsAffected 属性表示实际被更新的行数。如果更新的数据与原数据相同,RowsAffected 的值通常为 0,表示没有行被实际修改。
示例代码及解释
假设你有一个 ApiDictItemGroup 模型,并试图更新其 group_id 字段:
resag := tx.Model(&models.ApiDictItemGroup{}).Where("api_id = ?", api.ID).Update("group_id", groupId)
- 如果
groupId 与数据库中当前的 group_id 值相同:- resag.Error 是 nil,表示没有错误。
- resag.RowsAffected 的值为 0,因为没有实际修改任何行。
- 数据库不会执行实际的更新操作,因为没有数据变化。
- 如果
groupId 与数据库中当前的 group_id 值不同:- resag.Error 是 nil,表示没有错误。
- resag.RowsAffected 的值为 1,因为有一行数据被修改。
结论
当你尝试更新的数据与原数据相同时,RowsAffected 的值为 0。这表明没有行被实际修改,但操作是成功的。
建议
如果你需要确保某些逻辑仅在数据实际更改时执行,可以检查 resag.RowsAffected 的值是否大于 0。例如:
if resag.RowsAffected > 0 {
// 数据被实际修改,执行某些逻辑
}
四. Delete()
result2 := tx.Model(&models.ApiDictItemGroup{}).Where("api_id = ?", id).Delete(nil)
if result2.Error != nil {
tx.Rollback() // 回滚事务
return fmt.Errorf("DeleteApiRep -> 删除api_group表中的信息失败 -> %s", result2.Error)
}
如果要删除的数据不存在,result2.Error 的值是什么?
在 GORM 中,如果要删除的数据不存在(即删除条件未匹配到任何记录),result2.Error 的值通常为 nil,而不是一个具体的错误。这是因为 GORM 认为“未找到匹配记录”并不是一个错误,而是一个正常的操作结果。
在这种情况下,result2.RowsAffected 的值会是 0,表示没有行被删除。如果你需要根据是否删除了数据来判断操作是否成功,可以通过检查 result2.RowsAffected 来实现。
示例代码
result2 := tx.Model(&models.ApiDictItemGroup{}).Where("api_id = ?", id).Delete(nil)
if result2.Error != nil {
tx.Rollback() // 回滚事务
return fmt.Errorf("DeleteApiRep -> 删除api_group表中的信息失败 -> %s", result2.Error)
}
if result2.RowsAffected == 0 {
tx.Rollback() // 回滚事务
return fmt.Errorf("DeleteApiRep -> 删除api_group表中的信息失败 -> 未找到匹配的记录")
}
总结
- 如果删除条件未匹配到任何记录,result2.Error 的值是 nil。
- 如果需要判断是否删除了数据,可以通过检查 result2.RowsAffected 是否为 0 来实现。
- 如果 result2.Error 不为 nil,则表示删除操作失败,可能是由于其他错误(如数据库连接问题、SQL 执行错误等)。