GORM 提供了 Session 方法,这是一个 New Session Method,它允许创建带配置的新建会话模式:

  1. // Session 配置
  2. type Session struct {
  3. DryRun bool
  4. PrepareStmt bool
  5. NewDB bool
  6. Initialized bool
  7. SkipHooks bool
  8. SkipDefaultTransaction bool
  9. DisableNestedTransaction bool
  10. AllowGlobalUpdate bool
  11. FullSaveAssociations bool
  12. QueryFields bool
  13. Context context.Context
  14. Logger logger.Interface
  15. NowFunc func() time.Time
  16. CreateBatchSize int
  17. }

DryRun

生成 SQL 但不执行。 它可以用于准备或测试生成的 SQL,例如:

  1. // 新建会话模式
  2. stmt := db.Session(&Session{DryRun: true}).First(&user, 1).Statement
  3. stmt.SQL.String() //=> SELECT * FROM `users` WHERE `id` = $1 ORDER BY `id`
  4. stmt.Vars //=> []interface{}{1}
  5. // 全局 DryRun 模式
  6. db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{DryRun: true})
  7. // 不同的数据库生成不同的 SQL
  8. stmt := db.Find(&user, 1).Statement
  9. stmt.SQL.String() //=> SELECT * FROM `users` WHERE `id` = $1 // PostgreSQL
  10. stmt.SQL.String() //=> SELECT * FROM `users` WHERE `id` = ? // MySQL
  11. stmt.Vars //=> []interface{}{1}

你可以使用下面的代码生成最终的 SQL:

  1. // 注意:SQL 并不总是能安全地执行,GORM 仅将其用于日志,它可能导致会 SQL 注入
  2. db.Dialector.Explain(stmt.SQL.String(), stmt.Vars...)
  3. // SELECT * FROM `users` WHERE `id` = 1

预编译

PreparedStmt 在执行任何 SQL 时都会创建一个 prepared statement 并将其缓存,以提高后续的效率,例如:

  1. // 全局模式,所有 DB 操作都会创建并缓存预编译语句
  2. db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{
  3. PrepareStmt: true,
  4. })
  5. // 会话模式
  6. tx := db.Session(&Session{PrepareStmt: true})
  7. tx.First(&user, 1)
  8. tx.Find(&users)
  9. tx.Model(&user).Update("Age", 18)
  10. // returns prepared statements manager
  11. stmtManger, ok := tx.ConnPool.(*PreparedStmtDB)
  12. // 关闭 *当前会话* 的预编译模式
  13. stmtManger.Close()
  14. // 为 *当前会话* 预编译 SQL
  15. stmtManger.PreparedSQL // => []string{}
  16. // 为当前数据库连接池的(所有会话)开启预编译模式
  17. stmtManger.Stmts // map[string]*sql.Stmt
  18. for sql, stmt := range stmtManger.Stmts {
  19. sql // 预编译 SQL
  20. stmt // 预编译模式
  21. stmt.Close() // 关闭预编译模式
  22. }

NewDB

通过 NewDB 选项创建一个不带之前条件的新 DB,例如:

  1. tx := db.Where("name = ?", "jinzhu").Session(&gorm.Session{NewDB: true})
  2. tx.First(&user)
  3. // SELECT * FROM users ORDER BY id LIMIT 1
  4. tx.First(&user, "id = ?", 10)
  5. // SELECT * FROM users WHERE id = 10 ORDER BY id
  6. // 不带 `NewDB` 选项
  7. tx2 := db.Where("name = ?", "jinzhu").Session(&gorm.Session{})
  8. tx2.First(&user)
  9. // 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

  1. tx := db.Session(&gorm.Session{Initialized: true})

跳过钩子

如果您想跳过 钩子 方法,您可以使用 SkipHooks 会话模式,例如:

  1. DB.Session(&gorm.Session{SkipHooks: true}).Create(&user)
  2. DB.Session(&gorm.Session{SkipHooks: true}).Create(&users)
  3. DB.Session(&gorm.Session{SkipHooks: true}).CreateInBatches(users, 100)
  4. DB.Session(&gorm.Session{SkipHooks: true}).Find(&user)
  5. DB.Session(&gorm.Session{SkipHooks: true}).Delete(&user)
  6. DB.Session(&gorm.Session{SkipHooks: true}).Model(User{}).Where("age > ?", 18).Updates(&user)

禁用嵌套事务

在一个 DB 事务中使用 Transaction 方法,GORM 会使用 SavePoint(savedPointName)RollbackTo(savedPointName) 为你提供嵌套事务支持。 你可以通过 DisableNestedTransaction 选项关闭它,例如:

  1. db.Session(&gorm.Session{
  2. DisableNestedTransaction: true,
  3. }).CreateInBatches(&users, 100)

AllowGlobalUpdate

GORM 默认不允许进行全局 update/delete,该操作会返回 ErrMissingWhereClause 错误。 您可以通过将一个选项设置为 true 来启用它,例如:

  1. db.Session(&gorm.Session{
  2. AllowGlobalUpdate: true,
  3. }).Model(&User{}).Update("name", "jinzhu")
  4. // UPDATE users SET `name` = "jinzhu"

FullSaveAssociations

在创建、更新记录时,GORM 会通过 Upsert 自动保存关联及其引用记录。 如果您想要更新关联的数据,您应该使用 FullSaveAssociations 模式,例如:

  1. db.Session(&gorm.Session{FullSaveAssociations: true}).Updates(&user)
  2. // ...
  3. // INSERT INTO "addresses" (address1) VALUES ("Billing Address - Address 1"), ("Shipping Address - Address 1") ON DUPLICATE KEY SET address1=VALUES(address1);
  4. // INSERT INTO "users" (name,billing_address_id,shipping_address_id) VALUES ("jinzhu", 1, 2);
  5. // INSERT INTO "emails" (user_id,email) VALUES (111, "jinzhu@example.com"), (111, "jinzhu-2@example.com") ON DUPLICATE KEY SET email=VALUES(email);
  6. // ...

Context

通过 Context 选项,您可以传入 Context 来追踪 SQL 操作,例如:

  1. timeoutCtx, _ := context.WithTimeout(context.Background(), time.Second)
  2. tx := db.Session(&Session{Context: timeoutCtx})
  3. tx.First(&user) // 带有 context timeoutCtx 的查询操作
  4. tx.Model(&user).Update("role", "admin") // 带有 context timeoutCtx 的更新操作

GORM 也提供了简写形式的方法 WithContext,其实现如下:

  1. func (db *DB) WithContext(ctx context.Context) *DB {
  2. return db.Session(&Session{Context: ctx})
  3. }

自定义 Logger

Gorm 允许使用 Logger 选项自定义内建 Logger,例如:

  1. newLogger := logger.New(log.New(os.Stdout, "\r\n", log.LstdFlags),
  2. logger.Config{
  3. SlowThreshold: time.Second,
  4. LogLevel: logger.Silent,
  5. Colorful: false,
  6. })
  7. db.Session(&Session{Logger: newLogger})
  8. db.Session(&Session{Logger: logger.Default.LogMode(logger.Silent)})

查看 Logger 获取更多信息.

NowFunc

NowFunc 允许改变 GORM 获取当前时间的实现,例如:

  1. db.Session(&Session{
  2. NowFunc: func() time.Time {
  3. return time.Now().Local()
  4. },
  5. })

调试

Debug 只是将会话的 Logger 修改为调试模式的简写形式,其实现如下:

  1. func (db *DB) Debug() (tx *DB) {
  2. return db.Session(&Session{
  3. Logger: db.Logger.LogMode(logger.Info),
  4. })
  5. }

查询字段

声明查询字段

  1. db.Session(&gorm.Session{QueryFields: true}).Find(&user)
  2. // SELECT `users`.`name`, `users`.`age`, ... FROM `users` // 有该选项
  3. // SELECT * FROM `users` // 没有该选项

CreateBatchSize

默认批量大小

  1. users = [5000]User{{Name: "jinzhu", Pets: []Pet{pet1, pet2, pet3}}...}
  2. db.Session(&gorm.Session{CreateBatchSize: 1000}).Create(&users)
  3. // INSERT INTO users xxx (需 5 次)
  4. // INSERT INTO pets xxx (需 15 次)