• Gorm之gorm.io/gorm源码


    Gorm之gorm.io/gorm源码

    1.gorm.Open函数

    // Open initialize db session based on dialector
    //返回:gorm.DB结构体
    func Open(dialector Dialector, opts ...Option) (db *DB, err error) {
    	config := &Config{}
    
    	sort.Slice(opts, func(i, j int) bool {
    		_, isConfig := opts[i].(*Config)
    		_, isConfig2 := opts[j].(*Config)
    		return isConfig && !isConfig2
    	})
    
    	for _, opt := range opts {
    		if opt != nil {
    			if applyErr := opt.Apply(config); applyErr != nil {
    				return nil, applyErr
    			}
    			defer func(opt Option) {
    				if errr := opt.AfterInitialize(db); errr != nil {
    					err = errr
    				}
    			}(opt)
    		}
    	}
    
    	if d, ok := dialector.(interface{ Apply(*Config) error }); ok {
    		if err = d.Apply(config); err != nil {
    			return
    		}
    	}
    
    	if config.NamingStrategy == nil {
    		config.NamingStrategy = schema.NamingStrategy{}
    	}
    
    	if config.Logger == nil {
    		config.Logger = logger.Default
    	}
    
    	if config.NowFunc == nil {
    		config.NowFunc = func() time.Time { return time.Now().Local() }
    	}
    
    	if dialector != nil {
    		config.Dialector = dialector
    	}
    
    	if config.Plugins == nil {
    		config.Plugins = map[string]Plugin{}
    	}
    
    	if config.cacheStore == nil {
    		config.cacheStore = &sync.Map{}
    	}
    
    	db = &DB{Config: config, clone: 1}
    
    	db.callbacks = initializeCallbacks(db)
    
    	if config.ClauseBuilders == nil {
    		config.ClauseBuilders = map[string]clause.ClauseBuilder{}
    	}
    
    	if config.Dialector != nil {
    		err = config.Dialector.Initialize(db)
    	}
    
    	preparedStmt := &PreparedStmtDB{
    		ConnPool:    db.ConnPool,
    		Stmts:       map[string]Stmt{},
    		Mux:         &sync.RWMutex{},
    		PreparedSQL: make([]string, 0, 100),
    	}
    	db.cacheStore.Store(preparedStmtDBKey, preparedStmt)
    
    	if config.PrepareStmt {
    		db.ConnPool = preparedStmt
    	}
    
    	db.Statement = &Statement{
    		DB:       db,
    		ConnPool: db.ConnPool,
    		Context:  context.Background(),
    		Clauses:  map[string]clause.Clause{},
    	}
    
    	if err == nil && !config.DisableAutomaticPing {
    		if pinger, ok := db.ConnPool.(interface{ Ping() error }); ok {
    			err = pinger.Ping()
    		}
    	}
    
    	if err != nil {
    		config.Logger.Error(context.Background(), "failed to initialize database, got error %v", err)
    	}
    
    	return
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98

    2.gorm.Dialector接口

    // Dialector GORM database dialector
    type Dialector interface {
    	Name() string
    	Initialize(*DB) error
    	Migrator(db *DB) Migrator
    	DataTypeOf(*schema.Field) string
    	DefaultValueOf(*schema.Field) clause.Expression
    	BindVarTo(writer clause.Writer, stmt *Statement, v interface{})
    	QuoteTo(clause.Writer, string)
    	Explain(sql string, vars ...interface{}) string
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3.gorm.Config结构体

    // Config GORM config
    type Config struct {
    	// GORM perform single create, update, delete operations in transactions by default to ensure database data integrity
    	// You can disable it by setting `SkipDefaultTransaction` to true
    	SkipDefaultTransaction bool
    	// NamingStrategy tables, columns naming strategy
    	NamingStrategy schema.Namer
    	// FullSaveAssociations full save associations
    	FullSaveAssociations bool
    	// Logger
    	Logger logger.Interface
    	// NowFunc the function to be used when creating a new timestamp
    	NowFunc func() time.Time
    	// DryRun generate sql without execute
    	DryRun bool
    	// PrepareStmt executes the given query in cached statement
    	PrepareStmt bool
    	// DisableAutomaticPing
    	DisableAutomaticPing bool
    	// DisableForeignKeyConstraintWhenMigrating
    	DisableForeignKeyConstraintWhenMigrating bool
    	// DisableNestedTransaction disable nested transaction
    	DisableNestedTransaction bool
    	// AllowGlobalUpdate allow global update
    	AllowGlobalUpdate bool
    	// QueryFields executes the SQL query with all fields of the table
    	QueryFields bool
    	// CreateBatchSize default create batch size
    	CreateBatchSize int
    
    	// ClauseBuilders clause builder
    	ClauseBuilders map[string]clause.ClauseBuilder
    	// ConnPool db conn pool
    	ConnPool ConnPool
    	// Dialector database dialector
    	Dialector
    	// Plugins registered plugins
    	Plugins map[string]Plugin
    
    	callbacks  *callbacks
    	cacheStore *sync.Map
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    4.gorm.DB结构体

    4.1gorm.DB结构体

    // DB GORM DB definition
    type DB struct {
    	*Config      //gorm.Config结构体
    	Error        error
    	RowsAffected int64
    	Statement    *Statement
    	clone        int
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4.2AutoMigrate方法

    // AutoMigrate run auto migration for given models
    func (db *DB) AutoMigrate(dst ...interface{}) error {
    	return db.Migrator().AutoMigrate(dst...)
    }
    
    • 1
    • 2
    • 3
    • 4

    4.3Migrator方法

    // Migrator returns migrator
    func (db *DB) Migrator() Migrator {
    	tx := db.getInstance()
    
    	// apply scopes to migrator
    	for len(tx.Statement.scopes) > 0 {
    		scopes := tx.Statement.scopes
    		tx.Statement.scopes = nil
    		for _, scope := range scopes {
    			tx = scope(tx)
    		}
    	}
    
    	return tx.Dialector.Migrator(tx.Session(&Session{}))
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    4.4Create方法

    // Create insert the value into database
    func (db *DB) Create(value interface{}) (tx *DB) {
    	if db.CreateBatchSize > 0 {
    		return db.CreateInBatches(value, db.CreateBatchSize)
    	}
    
    	tx = db.getInstance()
    	tx.Statement.Dest = value
    	return tx.callbacks.Create().Execute(tx)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4.5CreateInBatches方法

    // CreateInBatches insert the value in batches into database
    func (db *DB) CreateInBatches(value interface{}, batchSize int) (tx *DB) {
    	reflectValue := reflect.Indirect(reflect.ValueOf(value))
    
    	switch reflectValue.Kind() {
    	case reflect.Slice, reflect.Array:
    		var rowsAffected int64
    		tx = db.getInstance()
    
    		callFc := func(tx *DB) error {
    			// the reflection length judgment of the optimized value
    			reflectLen := reflectValue.Len()
    			for i := 0; i < reflectLen; i += batchSize {
    				ends := i + batchSize
    				if ends > reflectLen {
    					ends = reflectLen
    				}
    
    				subtx := tx.getInstance()
    				subtx.Statement.Dest = reflectValue.Slice(i, ends).Interface()
    				subtx.callbacks.Create().Execute(subtx)
    				if subtx.Error != nil {
    					return subtx.Error
    				}
    				rowsAffected += subtx.RowsAffected
    			}
    			return nil
    		}
    
    		if tx.SkipDefaultTransaction {
    			tx.AddError(callFc(tx.Session(&Session{})))
    		} else {
    			tx.AddError(tx.Transaction(callFc))
    		}
    
    		tx.RowsAffected = rowsAffected
    	default:
    		tx = db.getInstance()
    		tx.Statement.Dest = value
    		tx = tx.callbacks.Create().Execute(tx)
    	}
    	return
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    4.6Save方法

    // Save update value in database, if the value doesn't have primary key, will insert it
    func (db *DB) Save(value interface{}) (tx *DB) {
    	tx = db.getInstance()
    	tx.Statement.Dest = value
    
    	reflectValue := reflect.Indirect(reflect.ValueOf(value))
    	switch reflectValue.Kind() {
    	case reflect.Slice, reflect.Array:
    		if _, ok := tx.Statement.Clauses["ON CONFLICT"]; !ok {
    			tx = tx.Clauses(clause.OnConflict{UpdateAll: true})
    		}
    		tx = tx.callbacks.Create().Execute(tx.Set("gorm:update_track_time", true))
    	case reflect.Struct:
    		if err := tx.Statement.Parse(value); err == nil && tx.Statement.Schema != nil {
    			for _, pf := range tx.Statement.Schema.PrimaryFields {
    				if _, isZero := pf.ValueOf(tx.Statement.Context, reflectValue); isZero {
    					return tx.callbacks.Create().Execute(tx)
    				}
    			}
    		}
    
    		fallthrough
    	default:
    		selectedUpdate := len(tx.Statement.Selects) != 0
    		// when updating, use all fields including those zero-value fields
    		if !selectedUpdate {
    			tx.Statement.Selects = append(tx.Statement.Selects, "*")
    		}
    
    		tx = tx.callbacks.Update().Execute(tx)
    
    		if tx.Error == nil && tx.RowsAffected == 0 && !tx.DryRun && !selectedUpdate {
    			result := reflect.New(tx.Statement.Schema.ModelType).Interface()
    			if err := tx.Session(&Session{}).Take(result).Error; errors.Is(err, ErrRecordNotFound) {
    				return tx.Create(value)
    			}
    		}
    	}
    
    	return
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    4.7First方法

    // First find first record that match given conditions, order by primary key
    func (db *DB) First(dest interface{}, conds ...interface{}) (tx *DB) {
    	tx = db.Limit(1).Order(clause.OrderByColumn{
    		Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey},
    	})
    	if len(conds) > 0 {
    		if exprs := tx.Statement.BuildCondition(conds[0], conds[1:]...); len(exprs) > 0 {
    			tx.Statement.AddClause(clause.Where{Exprs: exprs})
    		}
    	}
    	tx.Statement.RaiseErrorOnNotFound = true
    	tx.Statement.Dest = dest
    	return tx.callbacks.Query().Execute(tx)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4.8Take方法

    // Take return a record that match given conditions, the order will depend on the database implementation
    func (db *DB) Take(dest interface{}, conds ...interface{}) (tx *DB) {
    	tx = db.Limit(1)
    	if len(conds) > 0 {
    		if exprs := tx.Statement.BuildCondition(conds[0], conds[1:]...); len(exprs) > 0 {
    			tx.Statement.AddClause(clause.Where{Exprs: exprs})
    		}
    	}
    	tx.Statement.RaiseErrorOnNotFound = true
    	tx.Statement.Dest = dest
    	return tx.callbacks.Query().Execute(tx)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    4.9Last方法

    // Last find last record that match given conditions, order by primary key
    func (db *DB) Last(dest interface{}, conds ...interface{}) (tx *DB) {
    	tx = db.Limit(1).Order(clause.OrderByColumn{
    		Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey},
    		Desc:   true,
    	})
    	if len(conds) > 0 {
    		if exprs := tx.Statement.BuildCondition(conds[0], conds[1:]...); len(exprs) > 0 {
    			tx.Statement.AddClause(clause.Where{Exprs: exprs})
    		}
    	}
    	tx.Statement.RaiseErrorOnNotFound = true
    	tx.Statement.Dest = dest
    	return tx.callbacks.Query().Execute(tx)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    4.10Find方法

    // Find find records that match given conditions
    func (db *DB) Find(dest interface{}, conds ...interface{}) (tx *DB) {
    	tx = db.getInstance()
    	if len(conds) > 0 {
    		if exprs := tx.Statement.BuildCondition(conds[0], conds[1:]...); len(exprs) > 0 {
    			tx.Statement.AddClause(clause.Where{Exprs: exprs})
    		}
    	}
    	tx.Statement.Dest = dest
    	return tx.callbacks.Query().Execute(tx)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    4.11FindInBatches方法

    // FindInBatches find records in batches
    func (db *DB) FindInBatches(dest interface{}, batchSize int, fc func(tx *DB, batch int) error) *DB {
    	var (
    		tx = db.Order(clause.OrderByColumn{
    			Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey},
    		}).Session(&Session{})
    		queryDB      = tx
    		rowsAffected int64
    		batch        int
    	)
    
    	for {
    		result := queryDB.Limit(batchSize).Find(dest)
    		rowsAffected += result.RowsAffected
    		batch++
    
    		if result.Error == nil && result.RowsAffected != 0 {
    			tx.AddError(fc(result, batch))
    		} else if result.Error != nil {
    			tx.AddError(result.Error)
    		}
    
    		if tx.Error != nil || int(result.RowsAffected) < batchSize {
    			break
    		}
    
    		// Optimize for-break
    		resultsValue := reflect.Indirect(reflect.ValueOf(dest))
    		if result.Statement.Schema.PrioritizedPrimaryField == nil {
    			tx.AddError(ErrPrimaryKeyRequired)
    			break
    		}
    
    		primaryValue, _ := result.Statement.Schema.PrioritizedPrimaryField.ValueOf(tx.Statement.Context, resultsValue.Index(resultsValue.Len()-1))
    		queryDB = tx.Clauses(clause.Gt{Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey}, Value: primaryValue})
    	}
    
    	tx.RowsAffected = rowsAffected
    	return tx
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    4.12assignInterfacesToValue方法

    func (db *DB) assignInterfacesToValue(values ...interface{}) {
    	for _, value := range values {
    		switch v := value.(type) {
    		case []clause.Expression:
    			for _, expr := range v {
    				if eq, ok := expr.(clause.Eq); ok {
    					switch column := eq.Column.(type) {
    					case string:
    						if field := db.Statement.Schema.LookUpField(column); field != nil {
    							db.AddError(field.Set(db.Statement.Context, db.Statement.ReflectValue, eq.Value))
    						}
    					case clause.Column:
    						if field := db.Statement.Schema.LookUpField(column.Name); field != nil {
    							db.AddError(field.Set(db.Statement.Context, db.Statement.ReflectValue, eq.Value))
    						}
    					}
    				} else if andCond, ok := expr.(clause.AndConditions); ok {
    					db.assignInterfacesToValue(andCond.Exprs)
    				}
    			}
    		case clause.Expression, map[string]string, map[interface{}]interface{}, map[string]interface{}:
    			if exprs := db.Statement.BuildCondition(value); len(exprs) > 0 {
    				db.assignInterfacesToValue(exprs)
    			}
    		default:
    			if s, err := schema.Parse(value, db.cacheStore, db.NamingStrategy); err == nil {
    				reflectValue := reflect.Indirect(reflect.ValueOf(value))
    				switch reflectValue.Kind() {
    				case reflect.Struct:
    					for _, f := range s.Fields {
    						if f.Readable {
    							if v, isZero := f.ValueOf(db.Statement.Context, reflectValue); !isZero {
    								if field := db.Statement.Schema.LookUpField(f.Name); field != nil {
    									db.AddError(field.Set(db.Statement.Context, db.Statement.ReflectValue, v))
    								}
    							}
    						}
    					}
    				}
    			} else if len(values) > 0 {
    				if exprs := db.Statement.BuildCondition(values[0], values[1:]...); len(exprs) > 0 {
    					db.assignInterfacesToValue(exprs)
    				}
    				return
    			}
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    4.13FirstOrInit方法

    // FirstOrInit gets the first matched record or initialize a new instance with given conditions (only works with struct or map conditions)
    func (db *DB) FirstOrInit(dest interface{}, conds ...interface{}) (tx *DB) {
    	queryTx := db.Limit(1).Order(clause.OrderByColumn{
    		Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey},
    	})
    
    	if tx = queryTx.Find(dest, conds...); queryTx.RowsAffected == 0 {
    		if c, ok := tx.Statement.Clauses["WHERE"]; ok {
    			if where, ok := c.Expression.(clause.Where); ok {
    				tx.assignInterfacesToValue(where.Exprs)
    			}
    		}
    
    		// initialize with attrs, conds
    		if len(tx.Statement.attrs) > 0 {
    			tx.assignInterfacesToValue(tx.Statement.attrs...)
    		}
    	}
    
    	// initialize with attrs, conds
    	if len(tx.Statement.assigns) > 0 {
    		tx.assignInterfacesToValue(tx.Statement.assigns...)
    	}
    	return
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    4.14FirstOrCreate方法

    // FirstOrCreate gets the first matched record or create a new one with given conditions (only works with struct, map conditions)
    func (db *DB) FirstOrCreate(dest interface{}, conds ...interface{}) (tx *DB) {
    	queryTx := db.Limit(1).Order(clause.OrderByColumn{
    		Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey},
    	})
    	if tx = queryTx.Find(dest, conds...); tx.Error == nil {
    		if tx.RowsAffected == 0 {
    			if c, ok := tx.Statement.Clauses["WHERE"]; ok {
    				if where, ok := c.Expression.(clause.Where); ok {
    					tx.assignInterfacesToValue(where.Exprs)
    				}
    			}
    
    			// initialize with attrs, conds
    			if len(tx.Statement.attrs) > 0 {
    				tx.assignInterfacesToValue(tx.Statement.attrs...)
    			}
    
    			// initialize with attrs, conds
    			if len(tx.Statement.assigns) > 0 {
    				tx.assignInterfacesToValue(tx.Statement.assigns...)
    			}
    
    			return tx.Create(dest)
    		} else if len(db.Statement.assigns) > 0 {
    			exprs := tx.Statement.BuildCondition(db.Statement.assigns[0], db.Statement.assigns[1:]...)
    			assigns := map[string]interface{}{}
    			for _, expr := range exprs {
    				if eq, ok := expr.(clause.Eq); ok {
    					switch column := eq.Column.(type) {
    					case string:
    						assigns[column] = eq.Value
    					case clause.Column:
    						assigns[column.Name] = eq.Value
    					default:
    					}
    				}
    			}
    
    			return tx.Model(dest).Updates(assigns)
    		}
    	}
    	return tx
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    4.15Update方法

    // Update update attributes with callbacks, refer: https://gorm.io/docs/update.html#Update-Changed-Fields
    func (db *DB) Update(column string, value interface{}) (tx *DB) {
    	tx = db.getInstance()
    	tx.Statement.Dest = map[string]interface{}{column: value}
    	return tx.callbacks.Update().Execute(tx)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4.16Updates方法

    // Updates update attributes with callbacks, refer: https://gorm.io/docs/update.html#Update-Changed-Fields
    func (db *DB) Updates(values interface{}) (tx *DB) {
    	tx = db.getInstance()
    	tx.Statement.Dest = values
    	return tx.callbacks.Update().Execute(tx)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4.17UpdateColumn方法

    func (db *DB) UpdateColumn(column string, value interface{}) (tx *DB) {
    	tx = db.getInstance()
    	tx.Statement.Dest = map[string]interface{}{column: value}
    	tx.Statement.SkipHooks = true
    	return tx.callbacks.Update().Execute(tx)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4.18UpdateColumns方法

    func (db *DB) UpdateColumns(values interface{}) (tx *DB) {
    	tx = db.getInstance()
    	tx.Statement.Dest = values
    	tx.Statement.SkipHooks = true
    	return tx.callbacks.Update().Execute(tx)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4.19Delete方法

    // Delete delete value match given conditions, if the value has primary key, then will including the primary key as condition
    func (db *DB) Delete(value interface{}, conds ...interface{}) (tx *DB) {
    	tx = db.getInstance()
    	if len(conds) > 0 {
    		if exprs := tx.Statement.BuildCondition(conds[0], conds[1:]...); len(exprs) > 0 {
    			tx.Statement.AddClause(clause.Where{Exprs: exprs})
    		}
    	}
    	tx.Statement.Dest = value
    	return tx.callbacks.Delete().Execute(tx)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    4.20Count方法

    func (db *DB) Count(count *int64) (tx *DB) {
    
    • 1

    4.21Row()方法

    func (db *DB) Row() *sql.Row {
    	tx := db.getInstance().Set("rows", false)
    	tx = tx.callbacks.Row().Execute(tx)
    	row, ok := tx.Statement.Dest.(*sql.Row)
    	if !ok && tx.DryRun {
    		db.Logger.Error(tx.Statement.Context, ErrDryRunModeUnsupported.Error())
    	}
    	return row
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4.22Rows()方法

    func (db *DB) Rows() (*sql.Rows, error) {
    	tx := db.getInstance().Set("rows", true)
    	tx = tx.callbacks.Row().Execute(tx)
    	rows, ok := tx.Statement.Dest.(*sql.Rows)
    	if !ok && tx.DryRun && tx.Error == nil {
    		tx.Error = ErrDryRunModeUnsupported
    	}
    	return rows, tx.Error
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4.23Scan方法

    // Scan scan value to a struct
    func (db *DB) Scan(dest interface{}) (tx *DB) {
    	config := *db.Config
    	currentLogger, newLogger := config.Logger, logger.Recorder.New()
    	config.Logger = newLogger
    
    	tx = db.getInstance()
    	tx.Config = &config
    
    	if rows, err := tx.Rows(); err == nil {
    		if rows.Next() {
    			tx.ScanRows(rows, dest)
    		} else {
    			tx.RowsAffected = 0
    		}
    		tx.AddError(rows.Close())
    	}
    
    	currentLogger.Trace(tx.Statement.Context, newLogger.BeginAt, func() (string, int64) {
    		return newLogger.SQL, tx.RowsAffected
    	}, tx.Error)
    	tx.Logger = currentLogger
    	return
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    4.24Pluck方法

    // Pluck used to query single column from a model as a map
    //     var ages []int64
    //     db.Model(&users).Pluck("age", &ages)
    func (db *DB) Pluck(column string, dest interface{}) (tx *DB) {
    	tx = db.getInstance()
    	if tx.Statement.Model != nil {
    		if tx.Statement.Parse(tx.Statement.Model) == nil {
    			if f := tx.Statement.Schema.LookUpField(column); f != nil {
    				column = f.DBName
    			}
    		}
    	}
    
    	if len(tx.Statement.Selects) != 1 {
    		fields := strings.FieldsFunc(column, utils.IsValidDBNameChar)
    		tx.Statement.AddClauseIfNotExists(clause.Select{
    			Distinct: tx.Statement.Distinct,
    			Columns:  []clause.Column{{Name: column, Raw: len(fields) != 1}},
    		})
    	}
    	tx.Statement.Dest = dest
    	return tx.callbacks.Query().Execute(tx)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    4.25ScanRows方法

    func (db *DB) ScanRows(rows *sql.Rows, dest interface{}) error {
    	tx := db.getInstance()
    	if err := tx.Statement.Parse(dest); !errors.Is(err, schema.ErrUnsupportedDataType) {
    		tx.AddError(err)
    	}
    	tx.Statement.Dest = dest
    	tx.Statement.ReflectValue = reflect.ValueOf(dest)
    	for tx.Statement.ReflectValue.Kind() == reflect.Ptr {
    		elem := tx.Statement.ReflectValue.Elem()
    		if !elem.IsValid() {
    			elem = reflect.New(tx.Statement.ReflectValue.Type().Elem())
    			tx.Statement.ReflectValue.Set(elem)
    		}
    		tx.Statement.ReflectValue = elem
    	}
    	Scan(rows, tx, ScanInitialized)
    	return tx.Error
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    4.26Connection方法

    // Connection  use a db conn to execute Multiple commands,this conn will put conn pool after it is executed.
    func (db *DB) Connection(fc func(tx *DB) error) (err error) {
    	if db.Error != nil {
    		return db.Error
    	}
    
    	tx := db.getInstance()
    	sqlDB, err := tx.DB()
    	if err != nil {
    		return
    	}
    
    	conn, err := sqlDB.Conn(tx.Statement.Context)
    	if err != nil {
    		return
    	}
    
    	defer conn.Close()
    	tx.Statement.ConnPool = conn
    	return fc(tx)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    4.27Transaction方法

    // Transaction start a transaction as a block, return error will rollback, otherwise to commit.
    func (db *DB) Transaction(fc func(tx *DB) error, opts ...*sql.TxOptions) (err error) {}
    
    • 1
    • 2

    4.28Begin方法

    // Begin begins a transaction
    func (db *DB) Begin(opts ...*sql.TxOptions) *DB {}
    
    • 1
    • 2

    4.29Commit方法

    // Commit commit a transaction
    func (db *DB) Commit() *DB {
    	if committer, ok := db.Statement.ConnPool.(TxCommitter); ok && committer != nil && !reflect.ValueOf(committer).IsNil() {
    		db.AddError(committer.Commit())
    	} else {
    		db.AddError(ErrInvalidTransaction)
    	}
    	return db
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4.30Rollback方法

    // Rollback rollback a transaction
    func (db *DB) Rollback() *DB {}
    
    • 1
    • 2

    4.31SavePoint方法

    func (db *DB) SavePoint(name string) *DB {}
    
    • 1

    4.32RollbackTo方法

    func (db *DB) RollbackTo(name string) *DB {}
    
    • 1

    4.33Exec方法

    // Exec execute raw sql
    func (db *DB) Exec(sql string, values ...interface{}) (tx *DB) {}
    
    • 1
    • 2

    5.gorm.Option接口

    // Option gorm option interface
    type Option interface {
    	Apply(*Config) error
    	AfterInitialize(*DB) error
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    6.gorm.Migrator接口

    // Migrator migrator interface
    type Migrator interface {
    	// AutoMigrate
    	AutoMigrate(dst ...interface{}) error
    
    	// Database
    	CurrentDatabase() string
    	FullDataTypeOf(*schema.Field) clause.Expr
    
    	// Tables
    	CreateTable(dst ...interface{}) error
    	DropTable(dst ...interface{}) error
    	HasTable(dst interface{}) bool
    	RenameTable(oldName, newName interface{}) error
    	GetTables() (tableList []string, err error)
    
    	// Columns
    	AddColumn(dst interface{}, field string) error
    	DropColumn(dst interface{}, field string) error
    	AlterColumn(dst interface{}, field string) error
    	MigrateColumn(dst interface{}, field *schema.Field, columnType ColumnType) error
    	HasColumn(dst interface{}, field string) bool
    	RenameColumn(dst interface{}, oldName, field string) error
    	ColumnTypes(dst interface{}) ([]ColumnType, error)
    
    	// Views
    	CreateView(name string, option ViewOption) error
    	DropView(name string) error
    
    	// Constraints
    	CreateConstraint(dst interface{}, name string) error
    	DropConstraint(dst interface{}, name string) error
    	HasConstraint(dst interface{}, name string) bool
    
    	// Indexes
    	CreateIndex(dst interface{}, name string) error
    	DropIndex(dst interface{}, name string) error
    	HasIndex(dst interface{}, name string) bool
    	RenameIndex(dst interface{}, oldName, newName string) error
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    7.ColumnType接口

    // ColumnType column type interface
    type ColumnType interface {
    	Name() string
    	DatabaseTypeName() string                 // varchar
    	ColumnType() (columnType string, ok bool) // varchar(64)
    	PrimaryKey() (isPrimaryKey bool, ok bool)
    	AutoIncrement() (isAutoIncrement bool, ok bool)
    	Length() (length int64, ok bool)
    	DecimalSize() (precision int64, scale int64, ok bool)
    	Nullable() (nullable bool, ok bool)
    	Unique() (unique bool, ok bool)
    	ScanType() reflect.Type
    	Comment() (value string, ok bool)
    	DefaultValue() (value string, ok bool)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
  • 相关阅读:
    Cookie与Session
    【JavaEE】Spring Boot MyBatis详解(一)
    Vue中如何进行文件浏览与文件管理
    Vue3后台管理系统推荐
    自学了两年自动化门都没入?资料收藏家的名汇倒是锤实了,附入门教程...
    有人在双11疯狂剁手,有人在双11被直播“治愈”
    python+vue新生报到宿舍安排管理系统django flask
    【算法篇-数论】线性筛法(欧拉筛法)筛 n 以内的质数
    11-js事件基础
    信息安全工程师软考——第一章 网络信息安全概述笔记!!!!
  • 原文地址:https://blog.csdn.net/qq_53267860/article/details/125455873