xorm一次get请求

xorm的一次get请求做了什么?

func TestUser_Info(t *testing.T) {
	user := &model.User{}
	//var form *model.User
	println("BEFORE", unsafe.Pointer(user), unsafe.Pointer(&user.NickName))
	sql.Session().ID(1).Get(user)
	println("AFTER", unsafe.Pointer(user), unsafe.Pointer(&user.NickName))

}

在这里插入图片描述
运行测试方法,跟着断点调试下去
在这里插入图片描述
xorm中对get方法的描述是:从数据库中检索一条记录,检索的过程中会把非空字段当做条件。xorm认定非空字段条件:number != 0,string != “”,slice != nil,如果是自动关闭的回话,xorm会自动关闭它(默认为自动关闭的回话,所以在业务代码中基本不需要defer session.Close())
在这里插入图片描述
如果bean不是指针或者bean是指针同时bean的value也是指针,报错。这两种情况是大部分goalng 新手容易掉进去的坑,框架首先判断了这两种情况,通过值传递做的更改不算数。
在这里插入图片描述
这里调用了setRefBean 设置bean的引用,就是根据bean初始化一些参数。
在这里插入图片描述
方法调用了rValue去获得real value ,用了golang的反射,rValue调用了ValueOf,ValueOf函数返回一个Value类型值,该值代表运行时的数据。
在这里插入图片描述
调用ValueOf会发生指针逃逸,指针会从栈上逃到堆上 escapes(i)
*返回unpackEface(i),unpackEface会把空指针搞成一个实际对象(如果i为空的话),所以&User{},var user User没区别。
在这里插入图片描述
*TIPS:|= 是位运算符表示按位或后赋值。
在这里插入图片描述
得到实际值后,xorm调用autoMapType自动映射类型信息,这个函数有锁。首先尝试在engine.Tables中寻找t类型代表的表名字,如果有,使用,如果没有,自己映射一个,算个缓存吧。现在是第一次访问,进入if判断。
在这里插入图片描述
这个函数的目的是把下图的table信息获取出来。
在这里插入图片描述
在这里插入图片描述
调用tbNameForMap(v)
在这里插入图片描述
Implements会报告这个struct是否实现了TableName接口。如果实现了调用返回,这就是为什么Struct implement TableName 能够自定义表名。(下面代码顺序是错的只供阅读)


tpTableName = reflect.TypeOf((*TableName)(nil)).Elem()

// TableName table name interface to define customerize table name
type TableName interface {
	TableName() string
}

return v.Interface().(TableName).TableName()

如果没有实现,调用xorm中的Obj2Table,这又是另一组接口,可以自定义实现,随便怎么搞。
在这里插入图片描述
默认实现也有很多,能满足大部分需求。
在这里插入图片描述
在这里插入图片描述
跑完tbNameForMap(v),知道我们的表名了t_user,开始处理列,接下来是对某一列的处理。最终的目的是为了构造
在这里插入图片描述
这个结构体,首先看看这个属性有没有xorm这个tag 在这里插入图片描述
如果xorm不为空,先去处理tags
在这里插入图片描述
从代码来不同tag之间用空格分割。
在这里插入图片描述
循环对tags进行处理,如果当前的tag是-,忽略。现在我们的tags不是空 ,进入if,申明了一个tag context.
这里首先对xorm:"extends"进行了处理。
在这里插入图片描述
如果现在的字段是extends并且是一个结构体,那么递归调用mapType,如果当前的extends是一个指针,那么xorm会先把指针搞成struct,然后在进行mapType,这里有一个不大常用的golang 的关键字,fallthrouth,意思是继续执行下一个case而不去校验下一个条件是否符合。

在这里插入图片描述
继续向下会发现一个xorm的tagHandles,里面存放了每一种tag怎么处理。下图是默认的tag处理方式。
在这里插入图片描述

名称作用
<-只从db中取出来,不放进去
->和上面相反
PKprimary key主键约束
NULL列可以为空
NOTNOT
AUTOINCR自增
DEFAULT默认值
CREATED标记创建时间
UPDATED和上个功能类似
DELETED和上个功能类似,时间不为空默认表示被删除了
version乐观锁
UTC时区处理(没用过)
LOCAL本地时区
NOTNULL不能为空
INDEX是否是索引
UNIQUE是否唯一
CACHE当前字段缓存
NOCACHE不缓存
COMMENT注释

这里普及一下乐观锁和悲观锁
悲观锁,正如其名,它指的是对数据被外界(包括当前系统的其它事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排它性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。
乐观锁认为一般情况下数据不会造成冲突,所以在数据进行提交更新时才会对数据的冲突与否进行检测。如果没有冲突那就OK;如果出现冲突了,则返回错误信息并让用户决定如何去做。乐观锁的特点是先进行业务操作,不到万不得已不会去拿锁。乐观地认为拿锁多半会是成功的,因此在完成业务操作需要实际更新数据的最后一步再去拿一下锁。
乐观锁可以代码实现。
继续进行,下一步会判断sql type,也就是golang 的数据类型和sql之间的数据类型的转换。
在这里插入图片描述
在这里插入图片描述
上面图处理了所有的类型映射。下面是所有能够处理的数据库类型

Bit       = "BIT"
	TinyInt   = "TINYINT"
	SmallInt  = "SMALLINT"
	MediumInt = "MEDIUMINT"
	Int       = "INT"
	Integer   = "INTEGER"
	BigInt    = "BIGINT"

	Enum = "ENUM"
	Set  = "SET"

	Char             = "CHAR"
	Varchar          = "VARCHAR"
	NVarchar         = "NVARCHAR"
	TinyText         = "TINYTEXT"
	Text             = "TEXT"
	NText            = "NTEXT"
	Clob             = "CLOB"
	MediumText       = "MEDIUMTEXT"
	LongText         = "LONGTEXT"
	Uuid             = "UUID"
	UniqueIdentifier = "UNIQUEIDENTIFIER"
	SysName          = "SYSNAME"

	Date       = "DATE"
	DateTime   = "DATETIME"
	Time       = "TIME"
	TimeStamp  = "TIMESTAMP"
	TimeStampz = "TIMESTAMPZ"

	Decimal = "DECIMAL"
	Numeric = "NUMERIC"

	Real   = "REAL"
	Float  = "FLOAT"
	Double = "DOUBLE"

	Binary     = "BINARY"
	VarBinary  = "VARBINARY"
	TinyBlob   = "TINYBLOB"
	Blob       = "BLOB"
	MediumBlob = "MEDIUMBLOB"
	LongBlob   = "LONGBLOB"
	Bytea      = "BYTEA"

	Bool    = "BOOL"
	Boolean = "BOOLEAN"

	Serial    = "SERIAL"
	BigSerial = "BIGSERIAL"

	Json  = "JSON"
	Jsonb = "JSONB"
golangsql
int,int8,int16,int32,uint,uint8,uint32int
int64,uint64bigint
float32float
float64double
Complex64(复数),Complex128varchar
array,slice,map如果内容是byte用blob,其他的用text
boolbool
stringvarchar
struct结构体的处理是如果能转换成time.Time 就是time.Time如果不是,就是text
指针递归调用Type2SQLType()方法
如果这些都没有命中,那么默认的sql type 是text

在这里插入图片描述
类型映射完成之后,接下来映射列名,和表名类似,用的是一套接口。
在这里插入图片描述
上图是这个方法中对tag的处理,如果不存在tags 会进入到else中。在这里插入图片描述
上图所示,else中有个关键的地方是,xorm首先判断当前的field是否是可以寻址的,可寻址的数据类型有

an element of a slice
an element of an addressable array
a field of an addressable struct
the result of dereferencing a pointer.

在这里插入图片描述
上图是个有趣的写法,把Interface转换为core.Conversion来判断当前的结构是否实现了Conversion接口。
在这里插入图片描述
如果实现了Conversion接口就用实现的去作,如果没有实现就用默认的type2SQLType方法去作转化。这个地方变量命名好像有点问题,把ok改成notok更直观。一次循环结束的结果是构造了一个col对象,这时候table.AddColumn(col)
在这里插入图片描述
在这里插入图片描述
上图所示,这里对id有个特殊处理,就是说如果你的代码里没有特殊表示主键字段,那么ID就是主键。
在这里插入图片描述
随后处理缓存,顺便一提,xorm中使用的缓存算法是LRU算法,使用方法也很简单,API设置一下就行了

cacher := xorm.NewLRUCacher(xorm.NewMemoryStore(), 1000)
x.SetDefaultCacher(cacher)

当然你也可以换成自己的缓存算法。
在这里插入图片描述

这个时候mapType方法跑完了
在这里插入图片描述
EXTENDS也跑完了。
在这里插入图片描述
setRefBean也跑完了,这时候所有的信息已经准备好了,接下来就是连接数据库进行查询了。
查询之前好像还缺少数据库语句,那么接下来要作的事情就是根据之前得到的信息,构造出数据库语句。
在这里插入图片描述
首先判断一下是不是手写的语句,如果是手写的语句,就不要去genGetSql了,我们现在不是那么进入这个if判断。这时候我们运行的是get方法所以api偷偷给我们加上了一个Limit(1)
在这里插入图片描述
上图的方法是把之前生成的列信息搞成sql列,搞列的过程中,有些tags就起作用了如果是OnlyToDB的,就不会在这个查询中出现这个列。其中也有对表别名的处理。
在这里插入图片描述
有了列之后开始去添加查询条件,就像一开始所说的,如果struct中的属性不是zero那么会默认当成一个查询条件。
在这里插入图片描述
在这里插入图片描述
这个方法先判断是不是调用了noAutoCondition,如果是就不拼接自动生成的条件,如果不是去buildConds,
buildConds方法有点长,只要记住它作的事情就是把struct中不是zero的值拿出来按照规范拼接成查询条件就行了。
statement.cond = statement.cond.And(autoCond)
这里statement.cond对象是另外一个包的对象,在这里插入图片描述
这个包可以用golang 代码来写sql.
在这里插入图片描述
最后单独处理一下主键。
在这里插入图片描述
这里的buider对象是另外一个包的内容,这里不详细展开。
在这里插入图片描述
经过一系列转换之后,我们的sql语句拼接完成了,这时候可以去访问数据库了。在这里插入图片描述
访问之前看看是不是开启了缓存,如果开启了缓存,现在缓存中找找看。
在这里插入图片描述
如果这个缓存中能够找到记录,xorm会打印日志,平时我没有看到日志,也没有设置过缓存,所以缓存默认是关闭的状态。
在这里插入图片描述
接下来进入数据库访问的过程。
首先调用
在这里插入图片描述
最后调用
在这里插入图片描述
所以真正做事情的对象是DB这个对象,DB这个对象组合了,sql.DB底层还是用的golang 自己的sql包
在这里插入图片描述
在这里插入图片描述
上图所示这个时候已经查询完成了,现在就是把查询得到的值在赋值给bean,方法大致和之前类似。
在这里插入图片描述
最后查询之后放入缓存,至于用不用缓存就看用户设置了。
以上就是xorm中一次get的整个流程。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值