扫码一下
查看教程更方便
gorm 允许进行链式操作,所以我们可以像这样写代码
db.where("name = ?", "jinzhu").where("age = ?", 18).first(&user)
gorm 中有三种类型的方法: 链式方法
、终结方法
、新建会话方法
在 链式方法
, 终结方法
之后, gorm 返回一个初始化的 *gorm.db
实例,实例不能安全地重复使用,并且新生成的 sql 可能会被先前的条件污染,例如:
querydb := db.where("name = ?", "jinzhu")
querydb.where("age > ?", 10).first(&user)
// select * from users where name = "jinzhu" and age > 10
querydb.where("age > ?", 20).first(&user2)
// select * from users where name = "jinzhu" and age > 10 and age > 20
为了重新使用初始化的 *gorm.db
实例, 我们可以使用 新建会话方法
创建一个可共享的 *gorm.db
, 例如:
querydb := db.where("name = ?", "jinzhu").session(&gorm.session{})
querydb.where("age > ?", 10).first(&user)
// select * from users where name = "jinzhu" and age > 10
querydb.where("age > ?", 20).first(&user2)
// select * from users where name = "jinzhu" and age > 20
链式方法是将 clauses 修改或添加到当前 statement
的方法,例如:
where, select, omit, joins, scopes, preload, raw (raw can’t be used with other chainable methods to build sql)…
这是 ,也可以查看 sql 构建器 获取更多关于 clauses 的信息
终结(方法) 是会立即执行注册回调的方法,然后生成并执行 sql,比如这些方法:
gorm 定义了 session
、withcontext
、debug
方法做为 新建会话方法,查看会话 获取详情.
在 链式方法
, finisher
方法之后, gorm 返回一个初始化的 *gorm.db
实例,不能安全地再使用。我们应该使用 新建会话方法 来标记 *gorm.db
为可共享。
让我们用实例来解释它:
示例 1:
db, err := gorm.open(sqlite.open("test.db"), &gorm.config{})
// db is a new initialized `*gorm.db`, which is safe to reuse
db.where("name = ?", "jinzhu").where("age = ?", 18).find(&users)
// `where("name = ?", "jinzhu")` is the first chain method call, it will create an initialized `*gorm.db` instance, aka `*gorm.statement`
// `where("age = ?", 18)` is the second chain method call, it reuses the above `*gorm.statement`, adds new condition `age = 18` to it
// `find(&users)` is a finisher method, it executes registered query callbacks, which generates and runs the following sql:
// select * from users where name = 'jinzhu' and age = 18;
db.where("name = ?", "jinzhu2").where("age = ?", 20).find(&users)
// `where("name = ?", "jinzhu2")` is also the first chain method call, it creates a new `*gorm.statement`
// `where("age = ?", 20)` reuses the above `statement`, and add conditions to it
// `find(&users)` is a finisher method, it executes registered query callbacks, generates and runs the following sql:
// select * from users where name = 'jinzhu2' and age = 20;
db.find(&users)
// `find(&users)` is a finisher method call, it also creates a new `statement` and executes registered query callbacks, generates and runs the following sql:
// select * from users;
(错误的) 示例2:
db, err := gorm.open(sqlite.open("test.db"), &gorm.config{})
// db is a new initialized *gorm.db, which is safe to reuse
tx := db.where("name = ?", "jinzhu")
// `where("name = ?", "jinzhu")` returns an initialized `*gorm.statement` instance after chain method `where`, which is not safe to reuse
// good case
tx.where("age = ?", 18).find(&users)
// `tx.where("age = ?", 18)` use the above `*gorm.statement`, adds new condition to it
// `find(&users)` is a finisher method call, it executes registered query callbacks, generates and runs the following sql:
// select * from users where name = 'jinzhu' and age = 18
// bad case
tx.where("age = ?", 28).find(&users)
// `tx.where("age = ?", 18)` also use the above `*gorm.statement`, and keep adding conditions to it
// so the following generated sql is polluted by the previous conditions:
// select * from users where name = 'jinzhu' and age = 18 and age = 28;
示例 3:
db, err := gorm.open(sqlite.open("test.db"), &gorm.config{})
// db is a new initialized *gorm.db, which is 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` returns `*gorm.db` marked as safe to reuse, newly initialized `*gorm.statement` based on it keeps 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;