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

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 }

【gorm源码 -- 连接的申请与释放】若事务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 }

    推荐阅读