GORM 提供了 Session 方法,这是一个 New Session Method,它允许创建带配置的新建会话模式:
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,例如:
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 并将其缓存,以提高后续的效率,例如:
PreparedStmt
// 全局模式,所有 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,例如:
NewDB
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
Create a new initialized DB, which is not Method Chain/Goroutine Safe anymore, refer Method Chaining
tx := db.Session(&gorm.Session{Initialized: true})
如果您想跳过 钩子 方法,您可以使用 SkipHooks 会话模式,例如:
钩子
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 选项关闭它,例如:
Transaction
SavePoint(savedPointName)
RollbackTo(savedPointName)
DisableNestedTransaction
db.Session(&gorm.Session{ DisableNestedTransaction: true, }).CreateInBatches(&users, 100)
GORM 默认不允许进行全局 update/delete,该操作会返回 ErrMissingWhereClause 错误。 您可以通过将一个选项设置为 true 来启用它,例如:
ErrMissingWhereClause
db.Session(&gorm.Session{ AllowGlobalUpdate: true, }).Model(&User{}).Update("name", "jinzhu") // UPDATE users SET `name` = "jinzhu"
在创建、更新记录时,GORM 会通过 Upsert 自动保存关联及其引用记录。 如果您想要更新关联的数据,您应该使用 FullSaveAssociations 模式,例如:
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 操作,例如:
Context
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,其实现如下:
WithContext
func (db *DB) WithContext(ctx context.Context) *DB { return db.Session(&Session{Context: ctx}) }
Gorm 允许使用 Logger 选项自定义内建 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 获取当前时间的实现,例如:
NowFunc
db.Session(&Session{ NowFunc: func() time.Time { return time.Now().Local() }, })
Debug 只是将会话的 Logger 修改为调试模式的简写形式,其实现如下:
Debug
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 次)
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8