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 structfunc (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 queryingfunc 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 databasefunc 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 databasefunc (s *DB) Create(value interface{}) *DB {   scope := s.NewScope(value)   return scope.callCallbacks(s.parent.callbacks.creates).db}

插入语句有一系列的callbacks:

// Define callbacks for creatingfunc 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 transactionfunc (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或者rollbackfunc (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}