使用gorm需要注意的点
1、慎用CreatedAt、UpdatedAt和DeletedAt字段
数据库设计字段时要避开这created_at、updated_at、deleted_at字段,因为被框架本身使用了,建议改为created_time、updated_time和deleted_time。
数据插入时,仅仅插入业务数据即可,created_at
和updated_at
,deleted_at
字段不用手动设置值,gorm会自动维护
2、查询时,如果没有查到记录也算一个err,需要在正常理解的err之前判断,类似如下的顺序:
err := db.Table(GroupChatTableName).Select("gc_status").Where(map[string]interface{}{
"gc_id": gid,
}).Find(&group).Error
// 这个要在err前面,因为在gorm里找不到记录也算错误
if db.RecordNotFound() {
log.Errorf("query group chat not found")
return 0, nil
}
if err != nil {
log.Errorf("query group chat info by gid failed, err: %v", err)
return 0, err
}
Find查询结果是列表,First查询的是单条数据。
当 First、Last、Take 方法找不到记录时,GORM 会返回 ErrRecordNotFound 错误【jinzhu版】
注意:io版本 的 Find 函数在进行查找时,如果查找结果为空,不会报record not found
3、在使用Raw自定义SQL查询时,使用Scan来接收数据,虽然Find也是可以接收的,但是Find主要还是用来带条件查询的,链接到Raw后面时条件是不起作用的,所以用Scan函数单纯的接收数据就行了。
4、更新单个字段用struct+update,更新多个字段用struct+updates(不更新零值),必须通过 map+ updates才能更新多个字段,且零值字段也会更新。
5、Save用于保存所有字段。提示: 相当于根据主键id,更新所有模型字段值。如果记录在数据库中已经存在,Save 方法就会更新该记录。如果不存在,则会插入一条新记录。默认会更新该对象的所有字段,即使没有赋值
db.First(&user)
user.Name = "jinzhu 2"
user.Age = 100
db.Save(&user)
// UPDATE users SET name='jinzhu 2', age=100, birthday='2016-01-01', updated_at = '2013-11-17 21:34:10' WHERE id=111;
6、进行数据库操作时,要考虑数据安全问题,注意对输入参数进行有效性验证,以避免SQL注入等安全问题出现。
7、当通过结构体进行查询时,GORM将会只通过非零值字段查询,这意味着如果你的字段值为0
,''
,false
或者其他零值
时,将不会被用于构建查询条件,例如:
db.Where(&User{Name: "jinzhu", Age: 0}).Find(&users)
//SELECT * FROM users WHERE name = "jinzhu";
若要在查询条件中包含零值,可以使用映射,该映射将包含所有键值作为查询条件,例如:
db.Where(map[string]interface{}{"Name": "jinzhu", "Age": 0}).Find(&users)
// SELECT * FROM users WHERE name = "jinzhu" AND age = 0;
8、Count,该 model 能获取的记录总数。Count
必须是链式查询的最后一个操作 ,因为它会覆盖前面的 SELECT
,但如果里面使用了 count
时不会覆盖。
9、默认是软删除,只会将DeletedAt
字段的值会被设置为当前时间。如果要永久删除,则使用Unscoped
// Unscoped 方法可以物理删除记录
db.Unscoped().Delete(&order)
//DELETE FROM orders WHERE id=10;
10、where的使用
jinzhu版在调用Where
时会创建一个副本,同一个 DB 在多行调用 Where
函数时内容不会叠加
io版同一个 DB 在多行调用 Where
函数时内容会叠加
11、更新表达式,使用Expr函数
UPDATE foods SET stock = stock + 1 WHERE id = '2'
gorm提供了Expr函数用于设置表达式
db.Model(&food).Update("stock", gorm.Expr("stock + 1"))
//等价于: UPDATE `foods` SET `stock` = stock + 1 WHERE `foods`.`id` = '2'
12、日志大量出现 record not found
解决方式一:
db.Callback().Query().Before("gorm:query").Register("disable_raise_record_not_found", func(d *gorm.DB) {
d.Statement.RaiseErrorOnNotFound = false
})
解决方式二:
newLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
logger.Config{
SlowThreshold: time.Second, // Slow SQL threshold
LogLevel: logger.Silent, // Log level
IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound error for logger
ParameterizedQueries: true, // Don't include params in the SQL log
Colorful: false, // Disable color
},
)
// Globally mode
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{
Logger: newLogger,
})
// Continuous session mode
tx := db.Session(&Session{Logger: newLogger})
tx.First(&user)
tx.Model(&user).Update("Age", 18)
总结:
- 优点:提高开发效率
- 缺点:使用反射牺牲性能,牺牲灵活性
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」