gorm 阅读4
var users []dot1xDataItem
dot1xDb.Where("user_name = ? AND client_macaddr = ?", "test1", "88:A4:C2:D9:27:AE").Find(&users)
来看看这行代码是怎样组装sql语句
// Where add conditions
//
// See the [docs] for details on the various formats that where clauses can take. By default, where clauses chain with AND.
//
// // Find the first user with name jinzhu
// db.Where("name = ?", "jinzhu").First(&user)
// // Find the first user with name jinzhu and age 20
// db.Where(&User{Name: "jinzhu", Age: 20}).First(&user)
// // Find the first user with name jinzhu and age not equal to 20
// db.Where("name = ?", "jinzhu").Where("age <> ?", "20").First(&user)
//
// [docs]: https://gorm.io/docs/query.html#Conditions
func (db *DB) Where(query interface{}, args ...interface{}) (tx *DB) {
tx = db.getInstance()
if conds := tx.Statement.BuildCondition(query, args...); len(conds) > 0 {
tx.Statement.AddClause(clause.Where{Exprs: conds})
}
return
}
1、首先生成 build condition
[]clause.Expression{clause.Expr{SQL: s, Vars: args}}
// Expr raw expression
type Expr struct {
SQL string
Vars []interface{}
WithoutParentheses bool
}
2、AddClause 生成 stmt.Clauses[name] = c 对应的map
设置stmt.Clauses[”WHERE“] = c
// Where where clause
type Where struct {
Exprs []Expression // slice 变量
}
Exprs 为slice变量 也就是说可以是用多个where拼接
db.Where("name = ?", "jinzhu").Where("age <> ?", "20").First(&user)
3. Find 查找语句
// Find finds all records matching given conditions conds
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)
}
看代码Find 也是支持where 条件查找的
db.Find(&users, []int{1,2,3})
分析
// SELECT * FROM users WHERE id IN (1,2,3);
目标结构,根据其dest查找schema tx.Statement.Dest = dest
// Find finds all records matching given conditions conds
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)
}
对于传进来的参数是var users []dot1xDataItem Find(&users)
func (p *processor) Execute(db *DB) *DB {
stmt = db.Statement
stmt.BuildClauses = p.Clauses
stmt.Model = stmt.Dest
// parse model values 虽然传进来的user是nil的slice
//但是 &user 并不是nil
if stmt.Model != nil {
fmt.Printf(" stmt.Model:%+v \n", stmt.Model)
if err := stmt.Parse(stmt.Model);
}
// assign stmt.ReflectValue
if stmt.Dest != nil {
fmt.Printf(" stmt.Dest:%+v \n", stmt.Dest)
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()
}
/*
(dlv) p stmt.ReflectValue
reflect.Value {
typ: *reflect.rtype {size: 24, ptrdata: 8, hash: 2766611295, tflag: tflagExtraStar (2), align: 8, fieldAlign: 8, kind: 23, equal: nil, gcdata: *1, str: 40247, ptrToThis: 66240},
ptr: unsafe.Pointer(0xc000013278),
flag: 407,}
kind 为23 slice
*/
if !stmt.ReflectValue.IsValid() {
db.AddError(ErrInvalidValue)
}
}
// stmt.ReflectValue 为[]user 类型的值
for _, f := range p.fns {
f(db)
}
query
执行where之后以及执行find之前clause值为 如下:
Clauses: map[string]gorm.io/gorm/clause.Clause [
"WHERE": (*"gorm.io/gorm/clause.Clause")(0xc00010dc88),
],
BuildClauses: []string len: 7, cap: 7, [
"SELECT",
"FROM",
"WHERE",
"GROUP BY",
"ORDER BY",
"LIMIT",
"FOR",
],
func BuildQuerySQL(db *gorm.DB) {
db.Statement.AddClauseIfNotExists(clause.From{}) // from 对应的 struct
db.Statement.AddClauseIfNotExists(clauseSelect) //select 对应的struct
db.Statement.Build(db.Statement.BuildClauses...) // 根据db.Statement.BuildClauses 执行之前addClauses的build函数
/*
Clauses: map[string]gorm.io/gorm/clause.Clause [
"WHERE": (*"gorm.io/gorm/clause.Clause")(0xc00010dc88),
"FROM": (*"gorm.io/gorm/clause.Clause")(0xc00010dce0),
"SELECT": (*"gorm.io/gorm/clause.Clause")(0xc00010dd38),
],
BuildClauses: []string len: 7, cap: 7, [
"SELECT",
"FROM",
"WHERE",
"GROUP BY",
"ORDER BY",
"LIMIT",
"FOR",
],
*/
}
func Query(db *gorm.DB) {
if db.Error == nil {
BuildQuerySQL(db)
fmt.Printf(" query sql:%v \n", db.Statement.SQL.String())
if !db.DryRun && db.Error == nil {
rows, err := db.Statement.ConnPool.QueryContext(db.Statement.Context, db.Statement.SQL.String(), db.Statement.Vars...)
if err != nil {
db.AddError(err)
return
}
defer func() {
db.AddError(rows.Close())
}()
gorm.Scan(rows, db, 0)
}
}
}
sql 语句执行完后返回rows
gorm.Scan(rows, db, 0)
db.scanIntoStruct(rows, elem, values, fields, joinFields) {
for idx, field := range fields {
values[idx] = field.NewValuePool.Get()
rows.Scan(values...)
for idx, field := range fields {
field.Set(db.Statement.Context, reflectValue, values[idx])// 调用解析schema设置的set函数
// release data to pool
field.NewValuePool.Put(values[idx])
}
}
//之前ParseWithSpecialTableName 解析dest 获取schema后设置schema 每个字段 的set 方法 获取value 方法
//见 field.setupValuerAndSetter()
for initialized || rows.Next() {
db.scanIntoStruct(rows, elem, values, fields, joinFields)
reflectValue = reflect.Append(reflectValue, elem)
}
db.Statement.ReflectValue.Set(reflectValue)
=> gorm.Scan(rows, db, mode) 将查询结构 rows 放入 Scan函数返回
=> Scan(rows Rows, db *DB, mode ScanMode)
-> switch dest := db.Statement.Dest.(type) 根据 stmt 的 dest 类型设置怎么读 rows
-> rows.Next()-> db.RowsAffected++ -> rows.Scan(values...)
=> 类比原始 sql 操作
for rows.Next() {
err := rows.Scan(&id, &name)
if err != nil {
log.Fatal(err)
}
log.Println(id, name)
}
http代理服务器(3-4-7层代理)-网络事件库公共组件、内核kernel驱动 摄像头驱动 tcpip网络协议栈、netfilter、bridge 好像看过!!!!
但行好事 莫问前程
--身高体重180的胖子
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!