• 错误处理
    • 结果为空判断
    • 数据方法定义
    • 错误处理示例1
    • 错误处理示例2

    本章的部分特性需要 v1.8.0 版本以上支持。

    错误处理

    结果为空判断

    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