gorm 阅读3

gorm 相互关联

// Config GORM config
type Config struct {
    ----------
	Dialector
    --------
	callbacks  *callbacks
	cacheStore *sync.Map
}
// DB GORM DB definition
type DB struct {
	*Config
	Error        error
	RowsAffected int64
	Statement    *Statement
	clone        int
}

DB的Dialector 实现了AutoMigrate 接口

type Migrator struct {
	migrator.Migrator
}


// Migrator m struct
type Migrator struct {
	Config
}

// Config schema config
type Config struct {
	CreateIndexAfterCreateTable bool
	DB                          *gorm.DB
	gorm.Dialector
}

// AutoMigrate auto migrate values
func (m Migrator) AutoMigrate(values ...interface{})

//对于Statement  其存储在 cacheStore *sync.Map 

/*

创建表时:err := execTx.Migrator().CreateTable(value)
var execTx *gorm.DB  
execTx.Migrator()--->返回的tx.Dialector.Migratory 也就是返回Config --->Migrator 

此时execTx.Migrator().CreateTable(value)--->Migrator.CreateTable(value)
根据value在 stmt.DB.cacheStore.Load(schemaCacheKey) 

根据value 查找schema 结合db 赋值给stmt   statement


// Statement statement
type Statement struct {
	*DB
	TableExpr            *clause.Expr
	Table                string
	Model                interface{}
	Unscoped             bool
	Dest                 interface{}
	ReflectValue         reflect.Value
	Clauses              map[string]clause.Clause
	BuildClauses         []string
	Distinct             bool
	Selects              []string // selected columns
	Omits                []string // omit columns
	Joins                []join
	Preloads             map[string][]interface{}
	Settings             sync.Map
	ConnPool             ConnPool
	Schema               *schema.Schema
	Context              context.Context
	RaiseErrorOnNotFound bool
	SkipHooks            bool
	SQL                  strings.Builder
	Vars                 []interface{}
	CurDestIndex         int
	attrs                []interface{}
	assigns              []interface{}
	scopes               []func(*DB) *DB
}

 

var data1 dot1xDataItem
data1.UserName = "fp111"
data1.ClientMacAddr = "88:A4:C2:D9:27:AE"
data1.NasMacAddr = "48-4C-29-B2-B2-80"
data1.TunnelType = "VLAN1"
data1.TunnelMediumType = "IEEE-802"
data1.TunnelPrivateGroupID = "1100"
data1.FilterId = "accl11"
data1.UpdateAt = date

dot1xDb.Create(&data1)
func (p *processor) Execute(db *DB) *DB {
	
	// assign model values
	if stmt.Model == nil {
		stmt.Model = stmt.Dest
	} else if stmt.Dest == nil {
		stmt.Dest = stmt.Model
	}

	// parse model values
	if stmt.Model != nil {
		err := stmt.Parse(stmt.Model);  // load scheam
	}


	// assign stmt.ReflectValue
	if stmt.Dest != nil {  // 将dest的值 存储在relectvalue 在create hook 函数解析的时候,可以根据reflectvalue 以及filed 解析出值
		stmt.ReflectValue = reflect.ValueOf(stmt.Dest)
		for stmt.ReflectValue.Kind() == reflect.Ptr {
			if stmt.ReflectValue.IsNil() && stmt.ReflectValue.CanAddr() {
				stmt.ReflectValue.Set(reflect.New(stmt.ReflectValue.Type().Elem()))
			}

			stmt.ReflectValue = stmt.ReflectValue.Elem()
		}
	}

    for _, f := range p.fns {
		f(db)---//执行 RegisterDefaultCallbacks 中注册的create hook 
        /*
        	createCallback := db.Callback().Create()
	createCallback.Match(enableTransaction).Register("gorm:begin_transaction", BeginTransaction)
	createCallback.Register("gorm:before_create", BeforeCreate)
	createCallback.Register("gorm:save_before_associations", SaveBeforeAssociations(true))
	createCallback.Register("gorm:create", Create(config))
	createCallback.Register("gorm:save_after_associations", SaveAfterAssociations(true))
	createCallback.Register("gorm:after_create", AfterCreate)
        */ 
	}
}

当前processor 值:

可知:在调用create 插入数据时;

其stmt数据为:

crate 主要逻辑为创建Clauses;同时根据BuildClauses 组合sql语句

// Create create hook
func Create(config *Config) func(db *gorm.DB) {
	supportReturning := utils.Contains(config.CreateClauses, "RETURNING")

	return func(db *gorm.DB) {
		if db.Error != nil {
			return
		}


		if db.Statement.SQL.Len() == 0 {
			db.Statement.SQL.Grow(180)
			db.Statement.AddClauseIfNotExists(clause.Insert{})
			db.Statement.AddClause(ConvertToCreateValues(db.Statement))
			fmt.Printf("Clauses:%+v  \n BuildClauses:%+v \n sql:%v \n", db.Statement.Clauses, db.Statement.BuildClauses, db.Statement.SQL.String())
			db.Statement.Build(db.Statement.BuildClauses...)
			fmt.Printf(" after  sql:%v \n", db.Statement.SQL.String())
		}

			rows, err := db.Statement.ConnPool.QueryContext(
				db.Statement.Context, db.Statement.SQL.String(), db.Statement.Vars...,
			)
			if db.AddError(err) == nil {
				defer func() {
					db.AddError(rows.Close())
				}()
				gorm.Scan(rows, db, mode)
			}
			return
		}

		result, err := db.Statement.ConnPool.ExecContext(
			db.Statement.Context, db.Statement.SQL.String(), db.Statement.Vars...,
		)
		if err != nil {
			db.AddError(err)
			return
		}

		
	}
}

 

db.Statement.BuildClauses 为config processos里面需要执行的命令clause,  初始化时: 执行了 stmt.BuildClauses = p.Clauses   (p *processor
 
db.Statement.AddClauseIfNotExists(clause.Insert{})
db.Statement.AddClause(ConvertToCreateValues(db.Statement))
这两行代码实际上设置db.Statement.Clauses[name] = c      <---> 为当前支持stmt.Clauses[name] = c 支持的函数
 
db.Statement.AddClause(ConvertToCreateValues(db.Statement))
也就是设置 values 对应的函数接口,values 需要保存 columns 以及Values 
 
 
 
 
db.Statement.Build(db.Statement.BuildClauses...)  开始执行 insert  values 等组装
// Build build sql with clauses names
func (stmt *Statement) Build(clauses ...string) {
	var firstClauseWritten bool

	for _, name := range clauses {
		if c, ok := stmt.Clauses[name]; ok {
			if firstClauseWritten {
				stmt.WriteByte(' ')
			}

			firstClauseWritten = true
			if b, ok := stmt.DB.ClauseBuilders[name]; ok {
				b(c, stmt)
			} else {
				c.Build(stmt)
			}
		}
	}
}
对于INSERT 对应的ClauseBuilder 在初始化sql的时候初始化了
对应函数是:
 
在sqlite 初始化时,会初始化一部分sql  caluses  函数
for k, v := range dialector.ClauseBuilders() {
  db.ClauseBuilders[k] = v
}
 
 
  对于IVALUES 对应的ClauseBuilder 在初始化sql的时候没有初始化;
就会执行 c.Build(stmt) 这个 分支
 对应函数是:
// Build build clause
func (c Clause) Build(builder Builder) {
	if c.Builder != nil {
		c.Builder(c, builder)
	} else if c.Expression != nil {
		if c.BeforeExpression != nil {
			c.BeforeExpression.Build(builder)
			builder.WriteByte(' ')
		}

		if c.Name != "" {
			builder.WriteString(c.Name)
			builder.WriteByte(' ')
		}

		if c.AfterNameExpression != nil {
			c.AfterNameExpression.Build(builder)
			builder.WriteByte(' ')
		}

		c.Expression.Build(builder)

		if c.AfterExpression != nil {
			builder.WriteByte(' ')
			c.AfterExpression.Build(builder)
		}
	}
}

 此时会调用c.Expression.Build(builder)  由于 在mergeClause 时只初始化了Expression

由于 clause.Expression = values 值类型为  Values 执行 Values 对应的Build 函数

 

// Build build from clause
func (values Values) Build(builder Builder) {
	if len(values.Columns) > 0 {
		builder.WriteByte('(')
		for idx, column := range values.Columns {
			if idx > 0 {
				builder.WriteByte(',')
			}
			builder.WriteQuoted(column)
		}
		builder.WriteByte(')')

		builder.WriteString(" VALUES ")

		for idx, value := range values.Values {
			if idx > 0 {
				builder.WriteByte(',')
			}

			builder.WriteByte('(')
			builder.AddVar(builder, value...)
			builder.WriteByte(')')
		}
	} else {
		builder.WriteString("DEFAULT VALUES")
	}
}

values.Columns  以及 values.Values 写入sql string

最后调用 

rows, err := db.Statement.ConnPool.QueryContext(
  db.Statement.Context, db.Statement.SQL.String(), db.Statement.Vars...,
) 执行sql 语句

 

# 插入数据
result := db.WithContext(ctx).Create(&user)
=>db.Session(&Session{Context: ctx})->根据Session设置txConfig
		-> gorm.DB{txConfig数据库操作信息,Statement查询语句,RowsAffected结果,Error}
=>(db *DB) Create(value interface{}存放结果的内存地址) (tx *DB)
	  -> tx.Statement.Dest = value->tx.callbacks.Create().Execute(tx)
	  -> 走到上面设置的操作函数链
	  -> cs.processors["create"]::processor{db,fns,Clauses,callback}->Execute(tx)
	  => (p *processor) Execute(db *DB) *DB
	  		-> stmt.Model = stmt.Dest 设置输出的目标结构
	  		-> stmt.Parse(stmt.Model) 解析目标结构
	  		-> for f <- range p.fns:[f(db)]->执行之前注册的gorm:create函数,并把操作结果置入 db 结构内
	  		-> db.Logger.Trace
	  		
# gorm:create.Create(config)的执行
Create(config *Config) func(db *gorm.DB) 
=> 判断是否有需要补充的 Clause
=> db.Statement.AddClause(c)
=> rows, err := db.Statement.ConnPool.QueryContext(
				db.Statement.Context数据库操作上下文, db.Statement.SQL.String(), db.Statement.Vars...,)
=> gorm.ConnPool 设置四个接口函数[PrepareContext,ExecContext,QueryContext,QueryRowContext]
		->之前sql.Open开启的连接池持有的连接实现该四个函数
	-> func (tx *Tx) ExecContext(ctx, query string, args ...any) (Result, error) 
			->(db *DB) execDC(ctx dc *driverConn, release func(error), query string, args []any)
				->resultFromStatement(ctx, dc.ci, ds, args...) 处理stmt 内的参数
				-> ctxDriverStmtExec -> siCtx.ExecContext(ctx, nvdargs)
				-> 走到 go-sql-driver/mysql  
				-> (stmt *mysqlStmt) ExecContext(ctx context.Context, args []driver.NamedValue) 
						=> stmt.Exec(dargs)
								->err := stmt.writeExecutePacket(args) 执行 sql 
								->mc.readResultSetHeaderPacket() 读返回结果
										-> data, err := mc.readPacket()

原文链接:https://blog.csdn.net/u013010890/article/details/132613100

 

 

posted @   codestacklinuxer  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示