gorm的getInstance函数和成员变量db.clone

2024-08-21 16:36

本文主要是介绍gorm的getInstance函数和成员变量db.clone,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

db.clone的值控制函数getInstance是否返回新实例,一级新实列复制原实例的哪些数据。

问题

看下面一段代码,其中的三次查询为何不会相会影响,查询一的Where不会带到查询二和查询三。

package mainimport ("fmt""gorm.io/driver/sqlite""gorm.io/gorm"
)// 定义模型
type Product struct {gorm.ModelCode  stringPrice uint
}func main() {// 连接数据库db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})if err != nil {panic("failed to connect database")}// 自动迁移模式db.AutoMigrate(&Product{})// 插入3条示例数据db.Create(&Product{Code: "D42", Price: 100})db.Create(&Product{Code: "D43", Price: 200})db.Create(&Product{Code: "D44", Price: 300})// 根据不同条件查询var products []Product// 查询一db.Where("price > ?", 150).Find(&products) // 查询价格大于150的产品fmt.Println("Products with price > 150:", products)// 查询二db.Where("code LIKE ?", "%42%").Find(&products) // 查询代码包含42的产品fmt.Println("Products with code containing 42:", products)// 查询三db.Where("price BETWEEN ? AND ?", 100, 200).Find(&products) // 查询价格在100到200之间的产品fmt.Println("Products with price between 100 and 200:", products)
}

变量db.clone

// DB GORM DB definition
type DB struct {*ConfigError        errorRowsAffected int64Statement    *Statementclone        int
}

db.clone取值

截止版本,db.clone 只有三个取值,分别为 0、1 和 2 。

  • 取值0:

是默认值,表示当前实例不是克隆的,也没有开启事务。在这种情况下,所有的数据库操作都会直接应用到原始的数据库连接上。

  • 取值1:

创建一个新的 Statement 实例,并将当前数据库连接的一些属性(如连接池、上下文、语句片段、变量和跳过的钩子)复制到新的 Statement 实例中。

  • 取值2:

克隆当前数据库连接的 Statement 实例,并将新的 DB 实例设置为 Statement 的 DB 属性。

函数db.getInstance

func (db *DB) getInstance() *DB {// 当 db.clone > 0 时,返回一个新的 *DB 实例(tx)if db.clone > 0 {tx := &DB{Config: db.Config, Error: db.Error}if db.clone == 1 {// clone with new statementtx.Statement = &Statement{DB:        tx,ConnPool:  db.Statement.ConnPool,Context:   db.Statement.Context,Clauses:   map[string]clause.Clause{}, // 清空了,已设置的 where、join 等清空了Vars:      make([]interface{}, 0, 8), // 清空了SkipHooks: db.Statement.SkipHooks,}} else { // 必然是 db.clone == 2// with clone statementtx.Statement = db.Statement.clone() // 复制 Clauses、Vars、Joins 等,已设置的 where、join 等继续保留tx.Statement.DB = tx}return tx // 没有设置 tx.clone,因此 tx.clone 值为 0}// 当 db.clone <= 0 时,直接返回原始的 db 实例return db // 没对 db 做任何修改,因此 db.clone 值保持不变
}

Clauses

type Clause struct {Name                string // WHEREBeforeExpression    ExpressionAfterNameExpression ExpressionAfterExpression     ExpressionExpression          ExpressionBuilder             ClauseBuilder
}type Statement struct {Clauses              map[string]clause.ClauseVars                 []interface{}Joins                []joinOmits                []stringSelects              []string
}

Statement 中的 Clauses 是一个 map 类型,key 是字符串,value 是 clause.Clause 接口。它用于存储 SQL 查询中的各种子句(如 SELECT、FROM、WHERE、ORDER BY 等)。在构建 SQL 查询时,GORM 会根据这些子句生成对应的 SQL 语句。通过向 Clauses 添加或修改子句,可以灵活地自定义查询的行为。

设置db.clone值为1的函数

gorm.open函数

// Open initialize db session based on dialector
func Open(dialector Dialector, opts ...Option) (db *DB, err error) {db = &DB{Config: config, clone: 1}
}

db.Session函数

// Session create new db session
func (db *DB) Session(config *Session) *DB {var (txConfig = *db.Configtx       = &DB{Config:    &txConfig,Statement: db.Statement,Error:     db.Error,clone:     1,})
}

设置db.clone值为2的函数

db.Session函数

// Session create new db session
func (db *DB) Session(config *Session) *DB {if !config.NewDB {tx.clone = 2}
}

调用db.Session函数的函数

  • db.WithContext
// WithContext change current instance db's context to ctx
func (db *DB) WithContext(ctx context.Context) *DB {return db.Session(&Session{Context: ctx})
}

问题答案

看 Where 的实现,调用 db.getInstance 创建了新的实例。但因为 db.clone 的值为 1,因此新的实例会清空之前设置的 Where 等。

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
}

对于示例,因为每个 Where 都会创建新的实例,所以 Where 作用彼此间完全隔离的。Where 值作用在无关联的不同实例上,因此不会有任何相互影响。

附:观察db.cone的变化

函数 gorm.Open 会将 db.clone 值设置为 1,对于下列代码,db.cone、db2.cone、db3.cone、db4.cone、db5.cone、db6.cone、db7.cone 的值分别为多少?

//
db := gorm.Open(dsn)       // db.clone 值为 1
db1 := db                  // db1.clone 值为 1,db1 和 db 指向同一个地方,两者就是同一个对象
db2 := db.WithContext(ctx) // db2.clone 值为 2,db2 和 db 指向不同的地方,两者不是同一个对象
db3 := db.Table("t_test")  // db3.clone 值为 0,db3 和 db 指向不同的地方,两者不是同一个对象
db4 := db.Model(&User{})   // db4.clone 值为 0,db3 和 db 指向不同的地方,两者不是同一个对象
db5 := db.Find(&user)      // db5.clone 值为 0,db3 和 db 指向不同的地方,两者不是同一个对象
db6 := db.Begin()          // db6.clone 值为 1,db3 和 db 指向不同的地方,两者不是同一个对象
(dlv) p db.clone
1
(dlv) p db.clone
1
(dlv) p db1.clone
1
(dlv) p db2.clone
2
(dlv) p db3.clone
0
(dlv) p db4.clone
0
(dlv) p db5.clone
0
(dlv) p db6.clone
1(dlv) p &(*db)
("*gorm.io/gorm.DB")(0xc0001fe630)
(dlv) p &(*db1)
("*gorm.io/gorm.DB")(0xc0001fe630)
(dlv) p &(*db2)
("*gorm.io/gorm.DB")(0xc00028e1b0)
(dlv) p &(*db3)
("*gorm.io/gorm.DB")(0xc00028e330)
(dlv) p &(*db4)
("*gorm.io/gorm.DB")(0xc00028e420)
(dlv) p &(*db5)
("*gorm.io/gorm.DB")(0xc00028e4e0)
(dlv) p &(*db6)
("*gorm.io/gorm.DB")(0xc00028e7b0)

这篇关于gorm的getInstance函数和成员变量db.clone的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1093698

相关文章

MySQL数据库双机热备的配置方法详解

《MySQL数据库双机热备的配置方法详解》在企业级应用中,数据库的高可用性和数据的安全性是至关重要的,MySQL作为最流行的开源关系型数据库管理系统之一,提供了多种方式来实现高可用性,其中双机热备(M... 目录1. 环境准备1.1 安装mysql1.2 配置MySQL1.2.1 主服务器配置1.2.2 从

Python函数作用域与闭包举例深度解析

《Python函数作用域与闭包举例深度解析》Python函数的作用域规则和闭包是编程中的关键概念,它们决定了变量的访问和生命周期,:本文主要介绍Python函数作用域与闭包的相关资料,文中通过代码... 目录1. 基础作用域访问示例1:访问全局变量示例2:访问外层函数变量2. 闭包基础示例3:简单闭包示例4

深入理解Mysql OnlineDDL的算法

《深入理解MysqlOnlineDDL的算法》本文主要介绍了讲解MysqlOnlineDDL的算法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小... 目录一、Online DDL 是什么?二、Online DDL 的三种主要算法2.1COPY(复制法)

mysql8.0.43使用InnoDB Cluster配置主从复制

《mysql8.0.43使用InnoDBCluster配置主从复制》本文主要介绍了mysql8.0.43使用InnoDBCluster配置主从复制,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录1、配置Hosts解析(所有服务器都要执行)2、安装mysql shell(所有服务器都要执行)3、

k8s中实现mysql主备过程详解

《k8s中实现mysql主备过程详解》文章讲解了在K8s中使用StatefulSet部署MySQL主备架构,包含NFS安装、storageClass配置、MySQL部署及同步检查步骤,确保主备数据一致... 目录一、k8s中实现mysql主备1.1 环境信息1.2 部署nfs-provisioner1.2.

MySQL中VARCHAR和TEXT的区别小结

《MySQL中VARCHAR和TEXT的区别小结》MySQL中VARCHAR和TEXT用于存储字符串,VARCHAR可变长度存储在行内,适合短文本;TEXT存储在溢出页,适合大文本,下面就来具体的了解... 目录一、VARCHAR 和 TEXT 基本介绍1. VARCHAR2. TEXT二、VARCHAR

MySQL中C接口的实现

《MySQL中C接口的实现》本节内容介绍使用C/C++访问数据库,包括对数据库的增删查改操作,主要是学习一些接口的调用,具有一定的参考价值,感兴趣的可以了解一下... 目录准备mysql库使用mysql库编译文件官方API文档对象的创建和关闭链接数据库下达sql指令select语句前言:本节内容介绍使用C/

mybatis直接执行完整sql及踩坑解决

《mybatis直接执行完整sql及踩坑解决》MyBatis可通过select标签执行动态SQL,DQL用ListLinkedHashMap接收结果,DML用int处理,注意防御SQL注入,优先使用#... 目录myBATiFBNZQs直接执行完整sql及踩坑select语句采用count、insert、u

MySQL之搜索引擎使用解读

《MySQL之搜索引擎使用解读》MySQL存储引擎是数据存储和管理的核心组件,不同引擎(如InnoDB、MyISAM)采用不同机制,InnoDB支持事务与行锁,适合高并发场景;MyISAM不支持事务,... 目录mysql的存储引擎是什么MySQL存储引擎的功能MySQL的存储引擎的分类查看存储引擎1.命令

Python中isinstance()函数原理解释及详细用法示例

《Python中isinstance()函数原理解释及详细用法示例》isinstance()是Python内置的一个非常有用的函数,用于检查一个对象是否属于指定的类型或类型元组中的某一个类型,它是Py... 目录python中isinstance()函数原理解释及详细用法指南一、isinstance()函数