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

  1. // Session Configuration
  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

Initialized

Create a new initialized DB, which is not Method Chain/Gortoutine Safe anymore, refer Method Chaining

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

Skip Hooks

If you want to skip Hooks methods, you can use the SkipHooks session mode, for example:

  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)

DisableNestedTransaction

When using Transaction method inside a DB transaction, GORM will use SavePoint(savedPointName), RollbackTo(savedPointName) to give you the nested transaction support. You can disable it by using the DisableNestedTransaction option, for example:

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

AllowGlobalUpdate

GORM doesn’t allow global update/delete by default, will return ErrMissingWhereClause error. You can set this option to true to enable it, for example:

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

FullSaveAssociations

GORM will auto-save associations and its reference using Upsert when creating/updating a record. If you want to update associations’ data, you should use the FullSaveAssociations mode, for example:

  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

With the Context option, you can set the Context for following SQL operations, for example:

  1. timeoutCtx, _ := context.WithTimeout(context.Background(), time.Second)
  2. tx := db.Session(&Session{Context: timeoutCtx})
  3. tx.First(&user) // query with context timeoutCtx
  4. tx.Model(&user).Update("role", "admin") // update with context timeoutCtx

GORM also provides shortcut method WithContext, here is the definition:

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

Logger

Gorm allows customizing built-in logger with the Logger option, for example:

  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)})

Checkout Logger for more details.

NowFunc

NowFunc allows changing the function to get current time of GORM, for example:

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

Debug

Debug is a shortcut method to change session’s Logger to debug mode, here is the definition:

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

QueryFields

Select by fields

  1. db.Session(&gorm.Session{QueryFields: true}).Find(&user)
  2. // SELECT `users`.`name`, `users`.`age`, ... FROM `users` // with this option
  3. // SELECT * FROM `users` // without this option

CreateBatchSize

Default batch size

  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 batches)
  4. // INSERT INTO pets xxx (15 batches)