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,这确实是一个误导,实际上应该理解成todestination,可以解释为:将前面的查询结果输出到某个地方。

至于其他函数则可以调换位置,如:

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。