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 许可协议。转载请注明出处!