gorm使用Session()函数后where条件不生效
问题描述
下面query2
的Where条件在查询时不会生效
func main() {var data map[string]anyDB := simdb.InitGormMysql(dbConfig)//gorm初始化函数,请忽略query1 := DB.Model(&User{})query2 := query1.Session(&gorm.Session{})query2.Where("id =100")query2.Debug().Find(&data)
}
调试信息如下,可以看到query2
的where条件没有加上
[11.136ms] [rows:1] SELECT * FROM `sys_user`
正确写法:
通过修改Session配置可以让query2的where直接生效
query2 := query1.Session(&gorm.Session{Initialized: true, //让Initialized为true即可})
query2.Where('id =1')
query2.Where("name='张三'")
另一种,每次使用where函数,都接收一次它的返回值。
query2:=query1.Session(&gorm.Session{})
query2=query2.Where('id =1')
query2=query2.Where("name='张三'")
有人也喜欢这么写,建立新的查询时,用一次where条件,后面就不用每次都赋值了。
query2:= query1.Session(&gorm.Session{}).Where('id =1')
//下面不用每次都赋值了
query2.Where("name='张三'")
query2.Where("name='李四'")
上面两种写法,第一种更加规范,可以减少bug的出现频率。第二种,代码是变简单了,但是非常容易遗漏。
问题原因
看一下调用 Session函数 时的执行过程
func (db *DB) Session(config *Session) *DB {var (txConfig = *db.Config // 注意点1: 注意这里初始化了一个新的txConfigtx = &DB{Config: &txConfig,Statement: db.Statement,Error: db.Error,clone: 1,})//...省略部分代码//...//...//这里如果是false,不会生成新的实例。if config.Initialized { tx = tx.getInstance()}return tx
}
再来看where函数的代码:
func (db *DB) Where(query interface{}, args ...interface{}) (tx *DB) {// 这里生成了新的实例tx,而不是在原先的db基础上修改的tx = db.getInstance()if conds := tx.Statement.BuildCondition(query, args...); len(conds) > 0 {tx.Statement.AddClause(clause.Where{Exprs: conds})}return
}
首先通过Session和Where函数的代码对比,就知道该,把配置Session的Initialized设置为true,就能让where条件生效了(更深的细节文字不好描述,就不讲了):
func main() {var data map[string]anyDB := simdb.InitGormMysql(dbConfig)query1 := DB.Model(&User{})query2 := query1.Session(&gorm.Session{Initialized: true, //让Initialized为true即可})query2.Where("id =100")query2.Debug().Find(&data)
}
再看下官方文档,是这么写的:
根据官方示例,结合Session和Where函数的代码对比。我觉得开发者可能最初目的是为了减少db.getInstance()
函数的调用。。。
-
官方的这种查询方式,
tx.getInstance()
只会在Where中触发,总共触发了一次,queryDB := DB.Where( "name = ?" , "jinzhu" ).Session(&gorm.Session{}) queryDB.Where( "age > !" , 10 ).First(&user)
-
官方的这种查询方式,
tx.getInstance()
在Session和Where中都执行了,总共触发了两次,效率变差了…queryDB := DB.Where( "name = ?" , "jinzhu" ).Session(&gorm.Session{Initialized: true}) queryDB.Where( "age > !" , 10 ).First(&user)
但是这么设计,真的非常不友好…