前言
不知不觉入职也有1个月了,逐渐习惯了使用go语言开发,也在使用中遇到一些问题,就当作是月度总结好了。
总结
1. sql相关
sql单引号拼接问题:
尽量不要直接用%s、%d、%v之类的拼值,先拼?,?,?,?,然后直接传值,走sql包的赋值,会自动过滤sql注入,用可变参数的…展开参数。即使用2个切片,一个string类型切片,用来存储(?,?,?),一个空接口接收任意类型的切片,用来存储传给占位符?的参数,通过strings.Join()方法,将多个(?,?,?,?)传入%s,参数使用可变的空接口类型切片。
//eg.
_update = ‘UPDATE resource SET state=? WHERE group_id IN (%s)’
var(
sqls []string
args []interface{}
)
Args = append(args, model.ApplyNoAssignment)
for _, id := range ids {
sals = append(sals, “?”)
args = append(args, id)
}
res, err := tx.Exec(fmt.Sprintf(_update, strings.Join(sals, “,”)), args…)
批量insert问题:
在批量插入时,使用批量insert语句而非多条insert语句
# 批量INSERT INTO语句,这是正确的语法示例
INSERT INTO tb(col1,col2) VALUES(value1,values2),(value3,values4),(value5,values6);
rowStrings := make([]string, 0, len(wids))
rowArgs := make([]interface{}, 0)
ctime := time.Now()
for _, v := range wids {
rowStrings = append(rowStrings, "(?,?,?,?,?,?,?,?)")
rowArgs = append(rowArgs, item.Sid, v, item.Mid, item.Type, item.State, item.StickTop, ctime, ctime)
}
tx := d.DB.Begin()
if err = tx.Model(&model.Like{}).Exec(fmt.Sprintf(_likeBatchSQL, strings.Join(rowStrings, ",")), rowArgs...).Error; err != nil {
err = errors.Wrapf(err, " d.DB.Model(&model.Like{}).Exec(%s)", _likeBatchSQL)
tx.Rollback()
return
}
SQL的ErrNoRows问题:
Query不会返回ErrNoRows错误,因此不需要这个判断。只有QueryRow才会返回该错误
where可能存在重复的问题:
db:=d.DB.Model(&show.EntranceSave{}).Where(“state!=2”)
If state != _allList {
db = db.Where(“state=?”,state)
}
Db.Count(&res.Pager.Total)
//重复where条件,因写成如下形式:
db := d.DB.Model(&show.EntranceSave{})
if state != _allList {
db = db.Where("state=?", state)
} else {
db = db.Where("state!=2")
}
2. 对象初始化问题
写法一:
If err = d.mc.Get(c,key).Scan(attrsCache)
这种写法,传递的是对象本体,并且对象本地是个指针,因此必须对对象本体进行指针地址的初始化,方式如下:
//方式一:
attrsCache = new(model.EdgeAttrsCache)
//方式二:
attrsCache = &model.EdgeAttrsCache{}
写法二:
If err = d.mc.Get(c,key).Scan(&attrsCache)
这种写法传递的是对象本体的地址,在取对象地址时,就已经对对象本体初始化了,可以不再对对象本体进行额外初始化。
3. 空值判断
在公司mc生成器生成的代码中,一般对于查询成功但无记录现象置err为nil,因此在上层逻辑中就需要判断err==nil且res!=nil缓存命中才成功。db中当err不是nil时,直接返回
对于http接口获取的对象,需要进行空指针判断,防止对方接口对结构体或结构体中某个对象传递了nil,此时调用方将会panic
4.异步消费
当业务逻辑为read cache -> cache miss -> 回源 -> add cache,这是一个完全同步的过程,其中add cache可以塞到chan,给一个goroutine异步消费,最好不要同步add cache的逻辑。