关于gorm:gorm源码-连接的申请与释放

49次阅读

共计 4819 个字符,预计需要花费 13 分钟才能阅读完成。

gorm 封装了 go 自带的 database/sql,提供了不便操作的办法,然而其连贯的申请和开释还是应用 database/sql 中的实现。

查问语句的连贯申请与开释

查问语句的 code demo:

func GetHost(hid int) *Host {var hosts []Host
   dt := DBInstance.Table("host").Where("id > ?", hid).Scan(&hosts);
   if dt.Error != nil {fmt.Println("GetHost error:", dt.Error)
      return nil
   }
   if len(hosts) > 0 {return &hosts[0]
   } else {return nil}
}

DBInstance.Table(“host”) 设置表名,Where(“id > ?”, hid) 设置查问条件。

Scan(&hosts) 才真正的执行 sql 查问,包含 conn 申请、sql 执行、conn 开释。

// Scan scan value to a struct
func (s *DB) Scan(dest interface{}) *DB {
    // 后果存在 "gorm:query_destination" 对应的 value 上
    return s.NewScope(s.Value).Set("gorm:query_destination", dest).callCallbacks(s.parent.callbacks.queries).db    
}

查问语句的 callbacks:

// Define callbacks for querying
func init() {DefaultCallback.Query().Register("gorm:query", queryCallback)
   DefaultCallback.Query().Register("gorm:preload", preloadCallback)
   DefaultCallback.Query().Register("gorm:after_query", afterQueryCallback)
}

在 queryCallback 中进行了连贯的申请和开释:

// queryCallback used to query data from database
func queryCallback(scope *Scope) {
    ......
    // 取 "gorm:query_destination" 对应的 value
    if value, ok := scope.Get("gorm:query_destination"); ok {results = indirect(reflect.ValueOf(value))
    }
    ......
    // 这里调用底层 database/sql 的查问语句 (含获取连贯)
    if rows, err := scope.SQLDB().Query(scope.SQL, scope.SQLVars...); scope.Err(err) == nil {defer rows.Close()    // 这里开释连贯

        columns, _ := rows.Columns()
        for rows.Next() {
            scope.db.RowsAffected++

            elem := results
            if isSlice {elem = reflect.New(resultType).Elem()}
            scope.scan(rows, columns, scope.New(elem.Addr().Interface()).Fields())
            ......
    }
    ......
}

gorm 执行查问时,调用 database/sql 中的 Query 函数进行,内含连贯的申请。
gorm 开释连贯时,调用 database/sql 中的 rows.Close() 实现。

插入语句的连贯申请与开释

插入语句的 code demo:

func TestUser() {user := Test{Name: "胡海三"}
   dt := DBInstance.Table("test").Create(&user)
   if dt.Error != nil {fmt.Println("create user error:", dt.Error)
      return
   }
}

与查问操作相似,具体 sql 执行都是在 Create(&user) 中执行的:

// Create insert the value into database
func (s *DB) Create(value interface{}) *DB {scope := s.NewScope(value)
   return scope.callCallbacks(s.parent.callbacks.creates).db
}

插入语句有一系列的 callbacks:

// Define callbacks for creating
func init() {DefaultCallback.Create().Register("gorm:begin_transaction", beginTransactionCallback)
   DefaultCallback.Create().Register("gorm:before_create", beforeCreateCallback)
   DefaultCallback.Create().Register("gorm:save_before_associations", saveBeforeAssociationsCallback)
   DefaultCallback.Create().Register("gorm:update_time_stamp", updateTimeStampForCreateCallback)
   DefaultCallback.Create().Register("gorm:create", createCallback)
   DefaultCallback.Create().Register("gorm:force_reload_after_create", forceReloadAfterCreateCallback)
   DefaultCallback.Create().Register("gorm:save_after_associations", saveAfterAssociationsCallback)
   DefaultCallback.Create().Register("gorm:after_create", afterCreateCallback)
   DefaultCallback.Create().Register("gorm:commit_or_rollback_transaction", commitOrRollbackTransactionCallback)
}
  • beginTransactionCallback:开启事务,增加属性 ”gorm:started_transaction”;
  • beforeCreateCallback:调用用户自定义钩子:BeforeSave/BeforeCreate;
  • saveBeforeAssociationsCallback:解决关联关系;
  • updateTimeStampForCreateCallback:设置用户表的 create_at 和 update_at 字段;
  • createCallback:执行 sql 的插入操作;
  • forceReloadAfterCreateCallback:解决属性:gorm:blank_columns_with_default_value;
  • saveAfterAssociationsCallback:解决关联关系;
  • afterCreateCallback:调用用户自定义钩子:AfterCreate/AfterSave;
  • commitOrRollbackTransactionCallback:commit/rollback 事务,解决 gorm 属性:gorm:started_transaction;

具体到数据库连贯:

  • beginTransactionCallback:负责 connection 的申请;
  • commitOrRollbackTransactionCallback:负责 connection 的回收;

connection 的申请:beginTransactionCallback

func beginTransactionCallback(scope *Scope) {scope.Begin()
}
// Begin start a transaction
func (scope *Scope) Begin() *Scope {if db, ok := scope.SQLDB().(sqlDb); ok {if tx, err := db.Begin(); scope.Err(err) == nil {    // 这里申请数据库连贯
         scope.db.db = interface{}(tx).(SQLCommon)
         scope.InstanceSet("gorm:started_transaction", true)    // 增加了 "gorm:started_transaction" 属性
      }
   }
   return scope
}
func (db *DB) begin(ctx context.Context, opts *TxOptions, strategy connReuseStrategy) (tx *Tx, err error) {dc, err := db.conn(ctx, strategy)        // 调用底层的 database/sql 进行连贯的申请
   if err != nil {return nil, err}
   return db.beginDC(ctx, dc, dc.releaseConn, opts)    // 把 dc.releaseConn 函数传给 Tx
}

connection 的回收: commitOrRollbackTransactionCallback

func commitOrRollbackTransactionCallback(scope *Scope) {scope.CommitOrRollback()
}
// 依据是否产生谬误,进行 commit 或者 rollback
func (scope *Scope) CommitOrRollback() *Scope {if _, ok := scope.InstanceGet("gorm:started_transaction"); ok {if db, ok := scope.db.db.(sqlTx); ok {if scope.HasError() {db.Rollback()
         } else {scope.Err(db.Commit())
         }
         scope.db.db = scope.db.parent.db
      }
   }
   return scope
}

若事务 commit:

// Commit commits the transaction.
func (tx *Tx) Commit() error {
    ......
    var err error
    withLock(tx.dc, func() {err = tx.txi.Commit()
    })  
    tx.close(err)    // 这里开释连贯
    return err
}
func (tx *Tx) close(err error) {
   ......
   tx.releaseConn(err)        // 这里开释连贯,理论就是 dc.releaseConn()
   tx.dc = nil
   tx.txi = nil
}

若事务 rollback:

// Rollback aborts the transaction.
func (tx *Tx) Rollback() error {return tx.rollback(false)
}
func (tx *Tx) rollback(discardConn bool) error {
   ......
   withLock(tx.dc, func() {err = tx.txi.Rollback()
   })
   ....
   tx.close(err)        // 这里开释连贯,跟 Commit() 的流程雷同
   return err
}

正文完
 0