gorm是一款优秀的国产golang orm关系型数据库框架,在国内外使用比较广泛。它的链式调用还算是一种符合人类思维的风格。
不过在使用过程中也遇到一些困扰,比如:Model
, Find
, First
, Where
这些函数该什么时候使用,有时候会有边界不清楚,使用混乱的情况。
以下代码示例使用v2版本,v1和v2大体上相同,有些细微的不同
Where和Find
search := User{UserName:"月盾"}
db.Find(&user, search)
// SELECT * FROM `user` WHERE `user`.`user_name` = '月盾'
db.Where(search).Find(&user)
// SELECT * FROM `user` WHERE `user`.`user_name` = '月盾'
以上两种查询方式结果一样。
Find(dest interface{}, conds ...interface{})
Find函数有两个参数,dest是数据接收者,conds是查询条件。所以Find也是可以代替Where来传入条件的。
Where
的参数主要分为两类:String,Struct&Map。还有其他不常用类型。
String参数
当使用string参数时,使用方式类似于fmt.Printf
,第一个参数为字符串格式,使用?作为占位符,后面的参数作为值。
Struct&Map参数
使用结构体和映射作为参数时,则推荐一个参数即可,struct和map本身就是键值对格式。否则容易引起混淆。比如这样的:
db.Where(&User{Name: "jinzhu"}, "name", "Age").Find(&users)
// SELECT * FROM users WHERE name = "jinzhu" AND age = 0;
db.Where(&User{Name: "jinzhu"}, "Age").Find(&users)
// SELECT * FROM users WHERE age = 0;
注意 当使用结构作为条件查询时,GORM 只会查询非零值字段。这意味着如果您的字段值为 0、’’、false 或其他 零值,该字段不会被用于构建查询条件,例如:
db.Where(&User{Name: "jinzhu", Age: 0}).Find(&users)
// SELECT * FROM users WHERE name = "jinzhu";
你可以使用 map 来构建查询条件,它会使用所有的值,例如:
db.Where(map[string]interface{}{"Name": "jinzhu", "Age": 0}).Find(&users)
// SELECT * FROM users WHERE name = "jinzhu" AND age = 0;
Find和First
db.Find(&user)
// SELECT * FROM `user`
db.First(&user)
// SELECT * FROM `user` ORDER BY `user`.`id` LIMIT 1
Find查询结果是列表,First查询的是单条数据。
First(dest interface{}, conds ...interface{})
First参数和Find一样,同样可以传递条件参数。
Find和Scan
db.Raw("select * from user where id=?", 1).Find(&user)
db.Raw("select * from user where id=?", 1).Scan(&user)
在使用Raw自定义SQL查询时,使用Scan来接收数据,虽然Find也是可以接收的,但是Find主要还是用来带条件查询的,链接到Raw后面时条件是不起作用的。所以用Scan函数单纯的接收数据就行了。
Model()函数什么时候用?
对于查询来说,一般使用Find,First就够了。当查询链中没有用到Find,First等函数时,这时就无法指定要查询的表了,此时就要用Model来指定表。
另外的场景就是更新操作中使用。
Update(column string, value interface{})
更新函数的参数是(字段,值),没有能够确定表的参数,所以更新操作需要用到Model。
举例:
db.Model(&User{ID: 1}).Updates(User{Mobile: "13333333333"})
此时使用Model不仅可以指定表,还可以指定查询条件,但是这个条件却只能是id,不能使用其他条件。
像这样是不行的:
db.Model(&User{UserName: "月盾"}).Updates(User{Mobile: "13333333333"})
所以要使用其他条件就要用到Where函数了。
函数顺序
官网文档的示例中展示的例子都是这种格式:
db.Where("user_name = ?", "月盾").Find(&users)
// SELECT * FROM users WHERE user_name = '月盾';
你可能会想,Where和Find函数的顺序可以调换吗?答案是:不能!
对于Find函数,他的单词意义是:查找。很容易让人理解成SQL中的select
,这确实是一个误导,实际上应该理解成to
或destination
,可以解释为:将前面的查询结果输出到某个地方。
至于其他函数则可以调换位置,如:
db.Where("user_name = ?", "月盾").Order("id desc").Find(&user)
db.Order("id desc").Where("user_name = ?", "月盾").Find(&user)
// SELECT * FROM `user` WHERE user_name = '月盾' ORDER BY id desc
Where和Order的顺序则不影响最终输出SQL。