扫码一下
查看教程更方便
gorm 提供了 session
方法,这是一个 new session method,它允许创建带配置的新建会话模式:
// session 配置
type session struct {
dryrun bool
preparestmt bool
newdb bool
initialized bool
skiphooks bool
skipdefaulttransaction bool
disablenestedtransaction bool
allowglobalupdate bool
fullsaveassociations bool
queryfields bool
context context.context
logger logger.interface
nowfunc func() time.time
createbatchsize int
}
生成 sql 但不执行。 它可以用于准备或测试生成的 sql,例如:
// 新建会话模式
stmt := db.session(&session{dryrun: true}).first(&user, 1).statement
stmt.sql.string() //=> select * from `users` where `id` = $1 order by `id`
stmt.vars //=> []interface{}{1}
// 全局 dryrun 模式
db, err := gorm.open(sqlite.open("gorm.db"), &gorm.config{dryrun: true})
// 不同的数据库生成不同的 sql
stmt := db.find(&user, 1).statement
stmt.sql.string() //=> select * from `users` where `id` = $1 // postgresql
stmt.sql.string() //=> select * from `users` where `id` = ? // mysql
stmt.vars //=> []interface{}{1}
你可以使用下面的代码生成最终的 sql:
// 注意:sql 并不总是能安全地执行,gorm 仅将其用于日志,它可能导致会 sql 注入
db.dialector.explain(stmt.sql.string(), stmt.vars...)
// select * from `users` where `id` = 1
preparedstmt
在执行任何 sql 时都会创建一个 prepared statement 并将其缓存,以提高后续的效率,例如:
// 全局模式,所有 db 操作都会创建并缓存预编译语句
db, err := gorm.open(sqlite.open("gorm.db"), &gorm.config{
preparestmt: true,
})
// 会话模式
tx := db.session(&session{preparestmt: true})
tx.first(&user, 1)
tx.find(&users)
tx.model(&user).update("age", 18)
// returns prepared statements manager
stmtmanger, ok := tx.connpool.(*preparedstmtdb)
// 关闭 *当前会话* 的预编译模式
stmtmanger.close()
// 为 *当前会话* 预编译 sql
stmtmanger.preparedsql // => []string{}
// 为当前数据库连接池的(所有会话)开启预编译模式
stmtmanger.stmts // map[string]*sql.stmt
for sql, stmt := range stmtmanger.stmts {
sql // 预编译 sql
stmt // 预编译模式
stmt.close() // 关闭预编译模式
}
通过 newdb
选项创建一个不带之前条件的新 db,例如:
tx := db.where("name = ?", "jinzhu").session(&gorm.session{newdb: true})
tx.first(&user)
// select * from users order by id limit 1
tx.first(&user, "id = ?", 10)
// select * from users where id = 10 order by id
// 不带 `newdb` 选项
tx2 := db.where("name = ?", "jinzhu").session(&gorm.session{})
tx2.first(&user)
// select * from users where name = "jinzhu" order by id
创建一个新的初始化 db,它不再是 method chain/goroutine safe。
tx := db.session(&gorm.session{initialized: true})
如果想跳过 hook
方法,可以使用 skiphooks
会话模式,例如:
db.session(&gorm.session{skiphooks: true}).create(&user)
db.session(&gorm.session{skiphooks: true}).create(&users)
db.session(&gorm.session{skiphooks: true}).createinbatches(users, 100)
db.session(&gorm.session{skiphooks: true}).find(&user)
db.session(&gorm.session{skiphooks: true}).delete(&user)
db.session(&gorm.session{skiphooks: true}).model(user{}).where("age > ?", 18).updates(&user)
在一个 db 事务中使用 transaction
方法,gorm 会使用 savepoint(savedpointname)
,rollbackto(savedpointname)
为我们提供嵌套事务支持。 你可以通过 disablenestedtransaction
选项关闭它,例如:
db.session(&gorm.session{
disablenestedtransaction: true,
}).createinbatches(&users, 100)
allowglobalupdate
gorm 默认不允许进行全局 update/delete,该操作会返回 errmissingwhereclause 错误。 您可以通过将一个选项设置为 true 来启用它,例如:
db.session(&gorm.session{
allowglobalupdate: true,
}).model(&user{}).update("name", "jinzhu")
// update users set `name` = "jinzhu"
在创建、更新记录时,gorm 会通过 upsert 自动保存关联及其引用记录。 如果我们想要更新关联的数据,应该使用 fullsaveassociations
模式,例如:
db.session(&gorm.session{fullsaveassociations: true}).updates(&user)
// ...
// insert into "addresses" (address1) values ("billing address - address 1"), ("shipping address - address 1") on duplicate key set address1=values(address1);
// insert into "users" (name,billing_address_id,shipping_address_id) values ("jinzhu", 1, 2);
// insert into "emails" (user_id,email) values (111, "jinzhu@example.com"), (111, "jinzhu-2@example.com") on duplicate key set email=values(email);
// ...
通过 context 选项,我们可以传入 context 来追踪 sql 操作,例如:
timeoutctx, _ := context.withtimeout(context.background(), time.second)
tx := db.session(&session{context: timeoutctx})
tx.first(&user) // 带有 context timeoutctx 的查询操作
tx.model(&user).update("role", "admin") // 带有 context timeoutctx 的更新操作
gorm 也提供了简写形式的方法 withcontext
,其实现如下:
func (db *db) withcontext(ctx context.context) *db {
return db.session(&session{context: ctx})
}
gorm 允许使用 logger
选项自定义内建 logger,例如:
newlogger := logger.new(log.new(os.stdout, "\r\n", log.lstdflags),
logger.config{
slowthreshold: time.second,
loglevel: logger.silent,
colorful: false,
})
db.session(&session{logger: newlogger})
db.session(&session{logger: logger.default.logmode(logger.silent)})
查看 logger 获取更多信息。
nowfunc
允许改变 gorm 获取当前时间的实现,例如:
db.session(&session{
nowfunc: func() time.time {
return time.now().local()
},
})
debug 只是将会话的 logger 修改为调试模式的简写形式,其实现如下:
func (db *db) debug() (tx *db) {
return db.session(&session{
logger: db.logger.logmode(logger.info),
})
}
声明查询字段
db.session(&gorm.session{queryfields: true}).find(&user)
// select `users`.`name`, `users`.`age`, ... from `users` // 有该选项
// select * from `users` // 没有该选项
默认批量大小
users = [5000]user{{name: "jinzhu", pets: []pet{pet1, pet2, pet3}}...}
db.session(&gorm.session{createbatchsize: 1000}).create(&users)
// insert into users xxx (需 5 次)
// insert into pets xxx (需 15 次)