you are better than you think

pg.ErrNoRows和pg.ErrMultiRows

· by thur · Read in about 1 min · (179 Words)
golang pg.v4 ErrNoRows

golang pg.v4的Select,返回结果有可能是0行 1行或者多行,如果根据返回的行数进行下一步的insert 或update,应该怎么做?   如果使用

b:= &[]Book{}
err:= db.Model(b).Where("blabla").Select()

除非是数据库连接异常才会抛出error,而

b:= &Book{}
err:= db.Model(b).Where("blabla").Select()

会在select没有结果时抛出pg.ErrNoRows ,有多行时抛出pg.ErrMultiRows,1行时返回nil,数据库异常时error。 看下源码实现:

db.go

func (db *DB) Model(model interface{}) *orm.Query {
    return orm.NewQuery(db, model)
}

> orm/query.go

func NewQuery(db dber, v …interface{}) *Query {
    q := Query{
        db: db,
    }
    switch l := len(v); {
        case l == 1:
        v0 := v[0]
        if v0 != nil {
            q.model, q.err = newTableModel(v0)
        }
    ...
    }
    ...
    return &q
}

orm/model_table.go

func newTableModel(v interface{}) (tableModel, error) {
    switch v := v.(type) {
        ...
        case reflect.Value:
            return newTableModelValue(v)
        ...
    }
}
 
func newTableModelValue(v reflect.Value) (tableModel, error) {
    ...
    switch v.Kind() {
        case reflect.Struct:
            return newStructTableModel(v)
        case reflect.Slice:
            ...
        if elType.Kind() == reflect.Struct {
            return &sliceTableModel{
                structTableModel: structTableModel{
                    table: Tables.Get(elType),
                    root: v,
                },
                slice: v,
            }, nil
        }
    }
    ...

orm/query.go

func (q *Query) Select(values …interface{}) error {
    ...
    if m, ok := model.(useQueryOne); ok && m.useQueryOne() {
        _, err = q.db.QueryOne(model, sel, q.model)
    } else {
        _, err = q.db.Query(model, sel, q.model)
    }
    if err != nil {
        return err
    }
    ...

简单来说就是,当使用struct时,最终调用的时db的queryone() 而queryone函数中调用了assertone()函数对返回的结果行数进行了判断;而使用slice时,最终调用的时db的query()函数,query函数没有对返回的结果行数进行判断。

一点题外话,postgres9.5及以上版本提供selectorcreate /insertorupdate ,pg.v4 利用onconflict()实现,方便多了。

Comments