gorm package - gorm.io/gorm - Go Packages

关于 gorm.DB 的复用

func (db *DB) DB() 会返回一个db对象,该对象是可以复用的,而一旦查询开始后,接受者的状态会随着查询方法的调用而改变,例如:

tx := db.Table("tbl_name")
// &tx != &db,db状态没变,可以用db创建其他SQL

anotherTx := tx.Select("field")
// &anotherTx == &tx,tx状态改变了(添加了select条件),没办法复用tx创建另一个SQL

如果是手动事务,Begin()返回的DB对象是可以复用的:

	tx := db.Begin() // 开启事务
	
	fstTx := tx.Table("tbl_1") // &fstTx != &tx
	secTx := tx.Table("tbl_2") // &secTx != &tx != &fstTx
	fstTx = fstTx.Create("...") // fstTx 状态改变
	
	...
	
	tx.Commit() // 提交fstTx和secTx进行的SQL

GORM 中包含三种方法:链式方法,终结方法以及新会话方法。

链式方法 Chain Method 返回的gorm.DB对象不可重用,例如:Where(),Select(),Raw(),Joins()等等,因为它们会将新添加的SQL语句注册到调用它们的DB对象之中,返回的也是该DB对象。

终结方法 Finisher Method 例如Find(),Rows(),First()会实际执行SQL命令查询数据库。它返回的DB对象同样不可重用。

而新会话方法 New Session Method 返回的DB对象可以重用,例如:Session(),WithContext(),Debug()

db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
// 'db' is a newly initialized *gorm.DB, safe to reuse.

tx := db.Where("name = ?", "jinzhu").Session(&gorm.Session{})
// tx := db.Where("name = ?", "jinzhu").WithContext(context.Background())
// tx := db.Where("name = ?", "jinzhu").Debug()
// `Session`, `WithContext`, `Debug` methods return a `*gorm.DB` instance marked as safe for reuse. 
// They base a newly initialized `*gorm.Statement` on the current conditions.

// Good case
tx.Where("age = ?", 18).Find(&users)
// SELECT * FROM users WHERE name = 'jinzhu' AND age = 18

// Good case
tx.Where("age = ?", 28).Find(&users)
// SELECT * FROM users WHERE name = 'jinzhu' AND age = 28;

Method Chaining