# 會話
GORM 提供了 `Session` 方法,這是一個 [`新建會話方法`](http://v2.gorm.io/zh_CN/docs/method_chaining.html),它允許創建帶配置的新建會話模式:
```go
// 會話配置
type Session struct {
DryRun bool
PrepareStmt bool
WithConditions bool
Context context.Context
Logger logger.Interface
NowFunc func() time.Time
}
```
## DryRun
DarRun 模式會生成但不執行 `SQL`,可以用于準備或測試生成的 SQL,詳情請參考 Session:
```go
// 新建會話模式
stmt := db.Session(&Session{DryRun: true}).First(&user, 1).Statement
stmt.SQL.String() //=> SELECT * FROM `users` WHERE `id` = $1 ORDER BY `id`
stmt.Vars //=> []interface{}{1}
// 全局 DryRun 模式
db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{DryRun: true})
// 不同的數據庫生成不同的 SQL
stmt := db.Find(&user, 1).Statement
stmt.SQL.String() //=> SELECT * FROM `users` WHERE `id` = $1 // PostgreSQL
stmt.SQL.String() //=> SELECT * FROM `users` WHERE `id` = ? // MySQL
stmt.Vars //=> []interface{}{1}
```
## PrepareStmt
`PreparedStmt` 在執行任何 SQL 時都會創建一個 prepared statement 并將其緩存,以提高后續的效率,例如:
```go
// 全局模式,所有 DB 操作都會 創建并緩存 prepared stmt
db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{
PrepareStmt: true,
})
// 會話模式
tx := db.Session(&Session{PrepareStmt: true})
tx.First(&user, 1)
tx.Find(&users)
tx.Model(&user).Update("Age", 18)
// returns prepared statements manager
stmtManger, ok := tx.ConnPool.(*PreparedStmtDB)
// 關閉 *當前會話* 的 prepared statements
stmtManger.Close()
// 為 *當前會話* prepared SQL
stmtManger.PreparedSQL
// 開啟當前數據庫連接池(所有會話)的 prepared statements
stmtManger.Stmts // map[string]*sql.Stmt
for sql, stmt := range stmtManger.Stmts {
sql // prepared SQL
stmt // prepared statement
stmt.Close() // 關閉 prepared statement
}
```
## WithConditions
`WithCondition` 會共享 `*gorm.DB` 的條件,例如:
```go
tx := db.Where("name = ?", "jinzhu").Session(&gorm.Session{WithConditions: true})
tx.First(&user)
// SELECT * FROM users WHERE name = "jinzhu" ORDER BY id
tx.First(&user, "id = ?", 10)
// SELECT * FROM users WHERE name = "jinzhu" AND id = 10 ORDER BY id
// 不共享 `WithConditions`
tx2 := db.Where("name = ?", "jinzhu").Session(&gorm.Session{WithConditions: false})
tx2.First(&user)
// SELECT * FROM users ORDER BY id
```
## Context
`Context`,您可以通過 `Context` 來追蹤 SQL 操作,例如:
```go
timeoutCtx, _ := context.WithTimeout(context.Background(), time.Second)
tx := db.Session(&Session{Context: timeoutCtx})
tx.First(&user) // 帶 timeoutCtx 的查詢
tx.Model(&user).Update("role", "admin") // 帶 timeoutCtx 的更新
```
GORM 也提供快捷調用方法 `WithContext`,其實現如下:
```go
func (db *DB) WithContext(ctx context.Context) *DB {
return db.Session(&Session{WithConditions: true, Context: ctx})
}
```
## Logger
Gorm 允許使用 `Logger` 選項自定義內建 Logger,例如:
```go
newLogger := logger.New(log.New(os.Stdout, "\r\n", log.LstdFlags),
logger.Config{
SlowThreshold: time.Second,
LogLevel: logger.Silent,
Colorful: false,
})
db.Session(&Session{Logger: newLogger})
db.Session(&Session{Logger: logger.Default.LogMode(logger.Silent)})
```
查看 [Logger](http://v2.gorm.io/zh_CN/docs/logger.html) 獲取詳情
## NowFunc
`NowFunc` 允許改變 GORM 獲取當前時間的實現,例如:
```go
db.Session(&Session{
NowFunc: func() time.Time {
return time.Now().Local()
},
})
```
## Debug
`Debug` 只是將會話的 `Logger` 修改為調試模式的快捷方法,其實現如下:
```go
func (db *DB) Debug() (tx *DB) {
return db.Session(&Session{
WithConditions: true,
Logger: db.Logger.LogMode(logger.Info),
})
}
```