详解gorm中DB对象的clone属性
Gorm 版本:v1.22.4
Where函数源码
// Where add conditions
func (db *DB) Where(query interface{}, args ...interface{}) (tx *DB) {tx = db.getInstance()if conds := tx.Statement.BuildCondition(query, args...); len(conds) > 0 {tx.Statement.AddClause(clause.Where{Exprs: conds})}return
}func (db *DB) getInstance() *DB {if db.clone > 0 {tx := &DB{Config: db.Config, Error: db.Error}if db.clone == 1 {// clone with new statementtx.Statement = &Statement{DB: tx,ConnPool: db.Statement.ConnPool,Context: db.Statement.Context,Clauses: map[string]clause.Clause{},Vars: make([]interface{}, 0, 8),}} else {// with clone statementtx.Statement = db.Statement.clone()tx.Statement.DB = tx}return tx}return db
}
- db.Open() 使db的clone=1
- db.Begin() 使db的clone=1 (在https://github.com/go-gorm/gorm/pull/5012中修改为1,以前开启事务后clone是2)
- db.Where() 使db的clone=0
使用Where前(重点!!!)
- clone为1的话,是在新的数据库对象tx上构造查询条件(原db并没有修改),如果不接受Where()返回的tx,则会丢失构造的where条件;
- clone为0的话,是在调用where的db对象本身上构造查询条件,所以可以不用接受Where()返回值;
使用场景
- clone为0时,构造同一条sql,db对象使用多个where。
- clone为1时,构造不同的sql,该db对象调用多个where,它本身的clone一直会是1。调用的where返回的tx的clone是0。那我们每条sql都是从最初的db调用的where的返回值(tx对象,clone=0)开始,然后又到了第一种情况。
一般的使用顺序:先使用 db.Open()或db.Begin()(返回了新的 db2)去开一条新 sql,再在这个db2 上使用 Where()构造这条 sql。