Session
配置在 Gorm 中,Session
是一个配置结构体,用于在执行数据库操作时设置一些全局或会话级别的选项。这些选项可以影响 Gorm 的行为,例如是否启用事务、是否跳过钩子函数、是否启用预编译语句等。
Session
结构体字段解释gotype Session struct {
DryRun bool
PrepareStmt bool
NewDB bool
Initialized bool
SkipHooks bool
SkipDefaultTransaction bool
DisableNestedTransaction bool
AllowGlobalUpdate bool
FullSaveAssociations bool
QueryFields bool
Context context.Context
Logger logger.Interface
NowFunc func() time.Time
CreateBatchSize int
}
DryRun
: 如果设置为 true
,Gorm 将不会实际执行 SQL 语句,而是只生成 SQL 语句并返回。这在调试或测试时非常有用。
PrepareStmt
: 如果设置为 true
,Gorm 将使用预编译语句(Prepared Statements)来执行 SQL 查询。这可以提高性能,尤其是在多次执行相同查询时。
NewDB
: 如果设置为 true
,Gorm 将创建一个新的数据库连接,而不是使用现有的连接。这在需要隔离会话时非常有用。
Initialized
: 表示当前会话是否已经初始化。通常由 Gorm 内部使用。
SkipHooks
: 如果设置为 true
,Gorm 将跳过所有钩子函数(如 BeforeSave
, AfterSave
等)的执行。
SkipDefaultTransaction
: 如果设置为 true
,Gorm 将跳过默认的事务管理。默认情况下,Gorm 会在执行写操作(如 Create
, Update
, Delete
)时自动开启事务。
DisableNestedTransaction
: 如果设置为 true
,Gorm 将禁用嵌套事务。Gorm 默认支持嵌套事务,但可以通过此选项禁用。
AllowGlobalUpdate
: 如果设置为 true
,Gorm 将允许全局更新操作(即没有 WHERE
条件的 UPDATE
语句)。默认情况下,Gorm 会阻止这种操作以防止意外的全局更新。(Delete语句也是)
FullSaveAssociations
: 如果设置为 true
,Gorm 将在保存主模型时,自动保存所有关联的模型。这在处理复杂关联关系时非常有用。
QueryFields
: 如果设置为 true
,Gorm 将在查询时使用字段名而不是结构体字段名。这在处理字段名与数据库列名不一致时非常有用。
Context
: 用于传递上下文信息,通常用于控制超时、取消操作等。
Logger
: 用于自定义日志记录器。你可以通过此字段设置自定义的日志记录器,以便记录 Gorm 的操作日志。
NowFunc
: 用于自定义当前时间的函数。默认情况下,Gorm 使用 time.Now()
来获取当前时间,但你可以通过此字段自定义获取当前时间的方式。
CreateBatchSize
: 用于批量插入操作时,指定每次插入的记录数量。这在处理大量数据时非常有用,可以减少数据库的压力。
Session
的原理Session
结构体的主要作用是为 Gorm 提供一个配置接口,使得用户可以在执行数据库操作时动态地调整 Gorm 的行为。这些配置选项可以通过 Session
结构体传递给 Gorm 的各个操作方法。
例如,你可以在执行查询时启用 DryRun
模式,以便在不实际执行 SQL 语句的情况下查看生成的 SQL:
godb.Session(&gorm.Session{DryRun: true}).Find(&users)
在这个例子中,Gorm 将生成查询 users
表的 SQL 语句,但不会实际执行它。
在 Gorm 的源码中,Session
结构体通常作为参数传递给各种数据库操作方法。例如,在 gorm.DB
结构体中,有一个 Session
字段:
gotype DB struct {
...
Session *Session
...
}
当你调用 db.Session(&gorm.Session{...})
时,Gorm 会将这个 Session
配置应用到当前的 DB
实例中,从而影响后续的所有操作。
例如,在 gorm.DB
的 Find
方法中,Gorm 会检查 Session
配置,并根据配置决定是否执行 SQL 语句、是否使用预编译语句等:
gofunc (db *DB) Find(dest interface{}, conds ...interface{}) *DB {
...
if db.Session.DryRun {
// 生成 SQL 语句但不执行
...
} else {
// 执行 SQL 语句
...
}
...
}
我们可以看看db.Session会发生什么
go// Session create new db session
func (db *DB) Session(config *Session) *DB {
var (
txConfig = *db.Config // 复制当前 DB 的配置
tx = &DB{
Config: &txConfig, // 使用复制的配置创建新的 DB 实例
Statement: db.Statement, // 复制当前的 Statement
Error: db.Error, // 复制当前的错误信息
clone: 1, // 标记为克隆的 DB 实例
}
)
// 如果配置了 CreateBatchSize,则设置新的 DB 实例的 CreateBatchSize
if config.CreateBatchSize > 0 {
tx.Config.CreateBatchSize = config.CreateBatchSize
}
// 如果配置了 SkipDefaultTransaction,则设置新的 DB 实例的 SkipDefaultTransaction
if config.SkipDefaultTransaction {
tx.Config.SkipDefaultTransaction = true
}
// 如果配置了 AllowGlobalUpdate,则设置新的 DB 实例的 AllowGlobalUpdate
if config.AllowGlobalUpdate {
txConfig.AllowGlobalUpdate = true
}
// 如果配置了 FullSaveAssociations,则设置新的 DB 实例的 FullSaveAssociations
if config.FullSaveAssociations {
txConfig.FullSaveAssociations = true
}
// 如果配置了 PropagateUnscoped,则设置新的 DB 实例的 PropagateUnscoped
if config.PropagateUnscoped {
txConfig.PropagateUnscoped = true
}
// 如果配置了 Context、PrepareStmt 或 SkipHooks,则克隆 Statement
if config.Context != nil || config.PrepareStmt || config.SkipHooks {
tx.Statement = tx.Statement.clone()
tx.Statement.DB = tx
}
// 如果配置了 Context,则设置新的 Statement 的 Context
if config.Context != nil {
tx.Statement.Context = config.Context
}
// 如果配置了 PrepareStmt,则设置预编译语句
if config.PrepareStmt {
var preparedStmt *PreparedStmtDB
// 从缓存中加载或创建新的 PreparedStmtDB
if v, ok := db.cacheStore.Load(preparedStmtDBKey); ok {
preparedStmt = v.(*PreparedStmtDB)
} else {
preparedStmt = NewPreparedStmtDB(db.ConnPool)
db.cacheStore.Store(preparedStmtDBKey, preparedStmt)
}
// 根据当前连接池类型设置预编译语句
switch t := tx.Statement.ConnPool.(type) {
case Tx:
tx.Statement.ConnPool = &PreparedStmtTX{
Tx: t,
PreparedStmtDB: preparedStmt,
}
default:
tx.Statement.ConnPool = &PreparedStmtDB{
ConnPool: db.Config.ConnPool,
Mux: preparedStmt.Mux,
Stmts: preparedStmt.Stmts,
}
}
txConfig.ConnPool = tx.Statement.ConnPool
txConfig.PrepareStmt = true
}
// 如果配置了 SkipHooks,则设置新的 Statement 的 SkipHooks
if config.SkipHooks {
tx.Statement.SkipHooks = true
}
// 如果配置了 DisableNestedTransaction,则设置新的 DB 实例的 DisableNestedTransaction
if config.DisableNestedTransaction {
txConfig.DisableNestedTransaction = true
}
// 如果配置了 NewDB,则标记为新的 DB 实例
if !config.NewDB {
tx.clone = 2
}
// 如果配置了 DryRun,则设置新的 DB 实例的 DryRun
if config.DryRun {
tx.Config.DryRun = true
}
// 如果配置了 QueryFields,则设置新的 DB 实例的 QueryFields
if config.QueryFields {
tx.Config.QueryFields = true
}
// 如果配置了 Logger,则设置新的 DB 实例的 Logger
if config.Logger != nil {
tx.Config.Logger = config.Logger
}
// 如果配置了 NowFunc,则设置新的 DB 实例的 NowFunc
if config.NowFunc != nil {
tx.Config.NowFunc = config.NowFunc
}
// 如果配置了 Initialized,则获取新的 DB 实例
if config.Initialized {
tx = tx.getInstance()
}
// 返回新的 DB 实例
return tx
}
通过这种方式,Gorm 允许用户在运行时动态地调整数据库操作的行为,从而提供了极大的灵活性。
关于其他的,后面有时间再看一下,时间长不看容易忘
本文作者:yowayimono
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!