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}

6. // 全局 DryRun 模式
7. db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{DryRun: true})

9. // 不同的数据库生成不同的 SQL
10. stmt := db.Find(&user, 1).Statement
11. stmt.SQL.String() //=> SELECT * FROM `users` WHERE `id` = $1 // PostgreSQL
12. stmt.SQL.String() //=> SELECT * FROM `users` WHERE `id` = ?  // MySQL
13. 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. })

6. // 会话模式
7. tx := db.Session(&Session{PrepareStmt: true})
8. tx.First(&user, 1)
9. tx.Find(&users)
10. tx.Model(&user).Update("Age", 18)

12. // returns prepared statements manager
13. stmtManger, ok := tx.ConnPool.(*PreparedStmtDB)

15. // 关闭 *当前会话* 的预编译模式
16. stmtManger.Close()

18. // 为 *当前会话* 预编译 SQL
19. stmtManger.PreparedSQL // => []string{}

21. // 为当前数据库连接池的(所有会话)开启预编译模式
22. stmtManger.Stmts // map[string]*sql.Stmt

24. for sql, stmt := range stmtManger.Stmts {
25. sql  // 预编译 SQL
26. stmt // 预编译模式
27. stmt.Close() // 关闭预编译模式
28. }

NewDB

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

1. tx := db.Where("name = ?", "jinzhu").Session(&gorm.Session{NewDB: true})

3. tx.First(&user)
4. // SELECT * FROM users ORDER BY id LIMIT 1

6. tx.First(&user, "id = ?", 10)
7. // SELECT * FROM users WHERE id = 10 ORDER BY id

9. // 不带 `NewDB` 选项
10. tx2 := db.Where("name = ?", "jinzhu").Session(&gorm.Session{})
11. tx2.First(&user)
12. // 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)

3. DB.Session(&gorm.Session{SkipHooks: true}).Create(&users)

5. DB.Session(&gorm.Session{SkipHooks: true}).CreateInBatches(users, 100)

7. DB.Session(&gorm.Session{SkipHooks: true}).Find(&user)

9. DB.Session(&gorm.Session{SkipHooks: true}).Delete(&user)

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

4. tx.First(&user) // query with context timeoutCtx
5. 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})

9. 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}}...}

3. db.Session(&gorm.Session{CreateBatchSize: 1000}).Create(&users)
4. // INSERT INTO users xxx (5 batches)
5. // INSERT INTO pets xxx (15 batches)