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

  1. // 会话配置
  2. type Session struct {
  3. DryRun bool
  4. PrepareStmt bool
  5. WithConditions bool
  6. Context context.Context
  7. Logger logger.Interface
  8. NowFunc func() time.Time
  9. }

DryRun

DarRun 模式会生成但不执行 SQL,可以用于准备或测试生成的 SQL,详情请参考 Session:

  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}

PrepareStmt

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

  1. // 全局模式,所有 DB 操作都会 创建并缓存 prepared stmt
  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. // 关闭 *当前会话* 的 prepared statements
  13. stmtManger.Close()
  14. // 为 *当前会话* prepared SQL
  15. stmtManger.PreparedSQL
  16. // 开启当前数据库连接池(所有会话)的 prepared statements
  17. stmtManger.Stmts // map[string]*sql.Stmt
  18. for sql, stmt := range stmtManger.Stmts {
  19. sql // prepared SQL
  20. stmt // prepared statement
  21. stmt.Close() // 关闭 prepared statement
  22. }

WithConditions

WithCondition 会共享 *gorm.DB 的条件,例如:

  1. tx := db.Where("name = ?", "jinzhu").Session(&gorm.Session{WithConditions: true})
  2. tx.First(&user)
  3. // SELECT * FROM users WHERE name = "jinzhu" ORDER BY id
  4. tx.First(&user, "id = ?", 10)
  5. // SELECT * FROM users WHERE name = "jinzhu" AND id = 10 ORDER BY id
  6. // 不共享 `WithConditions`
  7. tx2 := db.Where("name = ?", "jinzhu").Session(&gorm.Session{WithConditions: false})
  8. tx2.First(&user)
  9. // SELECT * FROM users ORDER BY id

Context

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

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

GORM 也提供快捷调用方法 WithContext,其实现如下:

  1. func (db *DB) WithContext(ctx context.Context) *DB {
  2. return db.Session(&Session{WithConditions: true, 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

Debug 只是将会话的 Logger 修改为调试模式的快捷方法,其实现如下:

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