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)
