编辑
2024-10-21
后端
00
请注意,本文编写于 201 天前,最后修改于 200 天前,其中某些信息可能已经过时。

目录

Gorm 的 Session 配置
1. Session 结构体字段解释
2. Session 的原理
3. 源码

Gorm 的 Session 配置

在 Gorm 中,Session 是一个配置结构体,用于在执行数据库操作时设置一些全局或会话级别的选项。这些选项可以影响 Gorm 的行为,例如是否启用事务、是否跳过钩子函数、是否启用预编译语句等。

1. Session 结构体字段解释

go
type 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: 用于批量插入操作时,指定每次插入的记录数量。这在处理大量数据时非常有用,可以减少数据库的压力。

2. Session 的原理

Session 结构体的主要作用是为 Gorm 提供一个配置接口,使得用户可以在执行数据库操作时动态地调整 Gorm 的行为。这些配置选项可以通过 Session 结构体传递给 Gorm 的各个操作方法。

例如,你可以在执行查询时启用 DryRun 模式,以便在不实际执行 SQL 语句的情况下查看生成的 SQL:

go
db.Session(&gorm.Session{DryRun: true}).Find(&users)

在这个例子中,Gorm 将生成查询 users 表的 SQL 语句,但不会实际执行它。

3. 源码

在 Gorm 的源码中,Session 结构体通常作为参数传递给各种数据库操作方法。例如,在 gorm.DB 结构体中,有一个 Session 字段:

go
type DB struct { ... Session *Session ... }

当你调用 db.Session(&gorm.Session{...}) 时,Gorm 会将这个 Session 配置应用到当前的 DB 实例中,从而影响后续的所有操作。

例如,在 gorm.DBFind 方法中,Gorm 会检查 Session 配置,并根据配置决定是否执行 SQL 语句、是否使用预编译语句等:

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