错误处理

结果为空判断

GF框架v1.8.0之前的版本通过判断返回的结果集是否为nil来判断是否查询结果为空。

v1.8.0版本之后,对数据库操作的返回错误增加sql.ErrNoRows错误,因此可以通过判断返回的error结果是否等于sql.ErrNoRows来判断结果集是否为空(nil)。除此之外的其他错误为执行错误。

数据方法定义

首先我们需要对定义数据库读取的接口做一些说明。

我们来看一个方法定义:

  1. func GetPayedOrder() (gdb.Result, error) {
  2. r, err := g.DB().Table("order").Where("status", 1).All()
  3. if err != nil && err != sql.ErrNoRows {
  4. return nil, err
  5. }
  6. return r, nil
  7. }

也可以这样:

  1. func GetPayedOrder() (r gdb.Result, err error) {
  2. r, err = g.DB().Table("order").Where("status", 1).All()
  3. if err != nil && err == sql.ErrNoRows {
  4. err = nil
  5. }
  6. return
  7. }

这是Golang风格的方法定义,使用多返回值,并返回错误类型error。这种定义是Golang推荐的,并且也是严谨的方式,产生的错误努力往调用的上层抛,由调用方决定如何处理错误。当你无法决定如何处理产生的错误时,那就按照这样往上抛吧。

一般来说,应当由流程控制方法来决定如何处理该错误(例如:接口控制器),流程控制方法可以根据负责的业务需求决定,是否可以因为错误产生而终止执行流程,还是可以忽略错误(这时直接使用_符号忽略返回的错误变量即可)继续执行。

错误处理示例1

一些场景中,往往使用定义的结构体来管理数据集,例如这样的:

  1. type Order struct {
  2. Id int
  3. Status int
  4. PayedTime *gtime.Time
  5. CreateTime *gtime.Time
  6. }
  1. func GetPayedOrder() ([]*Order, error) {
  2. orders := ([]*Order)(nil)
  3. err := g.DB().Table("order").Where("status", 1).Structs(&orders)
  4. if err != nil && err != sql.ErrNoRows {
  5. return nil, err
  6. }
  7. return orders, nil
  8. }

也可以这样:

  1. func GetPayedOrder() (orders []*Order, err error) {
  2. err = g.DB().Table("order").Where("status", 1).Structs(&orders)
  3. if err != nil && err == sql.ErrNoRows {
  4. err = nil
  5. }
  6. return
  7. }

其中的数据集类型既可以使用orders []*Order,也可以使用orders []Order,两种定义方式没有太大的区分,喜好而定。

注意这里的err变量,当没有查询到数据时,是不会进行对象转换的,因此当没有数据时,会返回sql.ErrNoRows错误以便通知开发者没有数据。

这里还有一点细节,orders := ([]*Order)(nil)这样的初始化方式使得orders变量本身就是nil(预先没有执行对象初始化及内存分配),只有党查询到数据并且执行成功对象转换后orders才会有值(此时会自动分配内存),这是推荐的使用方式,这种方式对于GC来说比较友好。

错误处理示例2

单条记录的对象查询方式是这样的:

  1. func GetOrderInfo(id int) (*Order, error) {
  2. order := (*Order)(nil)
  3. err := g.DB().Table("order").Where("id", id).Struct(&order)
  4. if err != nil && err != sql.ErrNoRows {
  5. return nil, err
  6. }
  7. return order, nil
  8. }

也可以这样:

  1. func GetOrderInfo(id int) (order *Order, err error) {
  2. err = g.DB().Table("order").Where("id", id).Struct(&order)
  3. if err != nil && err == sql.ErrNoRows {
  4. err = nil
  5. }
  6. return
  7. }

同样的,只有当查询到数据记录之后,order才会执行内存分配,否则返回nil