3-Go操作redis(GoWeb进阶)
RedisRedis介绍Redis是一个开源的内存数据库,Redis提供了多种不同类型的数据结构,很多业务场景下的问题都可以很自然地映射到这些数据结构上。除此之外,通过复制、持久化和客户端分片等特性,我们可以很方便地将Redis扩展成一个能够包含数百GB数据、每秒处理上百万次请求的系统。
Redis支持的数据结构Redis支持诸如字符串(string)、哈希(hashe)、列表(list)、集合(set)、带范围查询的排序集合(sorted set)、bitmap、hyperloglog、带半径查询的地理空间索引(geospatial index)和流(stream)等数据结构。
Redis应用场景
缓存系统,减轻主数据库(MySQL)的压力。
计数场景,比如微博、抖音中的关注数和粉丝数。
热门排行榜,需要排序的场景特别适合使用ZSET。
利用 LIST 可以实现队列的功能。
利用 HyperLogLog 统计UV、PV等数据。
使用 geospatial index 进行地理位置相关查询。
12redis-server.exe redis.windows.confredis-cli ...
2-Go使用sqlx(GoWeb进阶)
Go使用sqlx在项目中我们通常可能会使用database/sql连接MySQL数据库。sqlx可以认为是Go语言内置database/sql的超集,它在优秀的内置database/sql基础上提供了一组扩展。
连接数据库123456789101112131415161718192021222324252627package mainimport ( "fmt" _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx")var db *sqlx.DBfunc initDB() (err error) { dsn := "root:password@tcp(127.0.0.1:3306)/web2?charset=utf8mb4&parseTime=True" // 也可以使用MustConnect连接不成功就panic db, err = sqlx.Connect("mysql", ...
1-Go操作MySQL(GoWeb进阶)
Go操作MySQL连接初始化连接sql.DB是表示连接的数据库对象(结构体实例),它保存了连接数据库相关的所有信息。它内部维护着一个具有零到多个底层连接的连接池,它可以安全地被多个goroutine同时使用。
1234567891011121314151617181920212223242526272829303132333435363738package mainimport ( "database/sql" "fmt" _ "github.com/go-sql-driver/mysql")// 定义一个全局对象dbvar db *sql.DB// 定义一个初始化数据库的函数func initDB() (err error) { // DSN:Data Source Name dsn := "root:password@tcp(127.0.0.1:3306)/web2?charset=utf8mb4&parseTime=True" // 不会校验账号密码是否正确 // 给全局变量赋值,然 ...
4-Golang幼麟实验室笔记(方法)
方法例子变量a称为方法接收者,会作为方法Name()的第一个参数传入。
Go语言中函数类型只和参数与返回值相关。
方法本质上就是普通的函数,接收者是隐含的第一个参数。
1234567891011121314type A struct { name string}func (a A) Name() string { a.name = "Hi " + a.name return a.name}func main() { a := A{name: "itxiaoma"} fmt.Println(a.Name()) //Hi itxiaoma fmt.Println(A.Name(a)) //Hi itxiaoma}
123456789101112131415161718192021type A struct { name string}func (a A) Name() string { a.name = "Hi & ...
3-Golang幼麟实验室笔记(闭包)
闭包Function Valuego中函数是头等对象,可以作为参数传递,可以作为返回值,也可以绑定到变量。go中称这样的参数,返回值或者变量为Function Value。
Function Value本质上是一个指针,却不直接指向函数指令入口,而是指向runtime.funcval结构体,这个结构体里只有一个地址,就是这个函数指令的入口地址。
函数A被赋值给f1和f2两个变量,这种情况,编译器会做出优化,让f1和f2共用一个funcval结构体。
如果函数A的指令在这,入口地址addr1,编译阶段,会在只读数据段分配一个funcval结构体,fn指向函数A指令入口,而它本身的起始地址,会在执行阶段赋给f1和f2。通过f1来执行函数,就会通过它存储的地址找到对应的funcval结构体,拿到函数入口地址,然后调转执行。
既然只要有函数入口地址就能调用 ,为什么要通过funcval结构体包装这个地址,然后使用一个二级指针来调用呢?这里主要是为了处理闭包的情况。
闭包
第一:必须要有在函数外部定义,但在函数内部引用的自由变量。
第二:脱离了形成闭包的上下文,闭包也能照常使用这些自由变量。 ...
2-Golang幼麟实验室笔记(函数调用栈)
函数调用栈我们在编程中写的函数,会被编译器编译为机器指令,写入可执行文件,程序执行的时候,会把这个可执行文件加载到内存,在虚拟地址空间中的代码段存放。
如果在一个函数中调用另一个函数,编译器就会对应生成一条call指令,当程序执行到这条call指令时,就会跳到对应的函数入口处开始执行,而每一个函数的最后,都有一条ret指令,负责在函数结束后跳回到调用处继续执行。
栈区函数执行的时候需要有足够的内存空间来存放局部变量,参数,返回值等数据,这些数据存在上图中的栈中。
栈先入后出,先入栈的在底部。
虚拟地址空间的栈区,上面是高地址,下面是低地址,栈底通常称为栈基,栈顶又叫栈指针。
具体的栈帧布局是:
调用者栈基地址(也就是谁调用了这个函数)
局部变量
调用函数的返回值
参数
通过栈指针加上偏移来定位到每个参数和返回值。
比如栈指针+8字节处,就是栈指针的上一格,通过这种方式来进行偏移。
当在A函数中调用B函数时,会在A函数中插入一条call指令,当执行到call指令的时候,会去B函数开始处运行。那么call指令做的事情就是:
首先把A函数中下一条指令的地址入栈(栈基地址,当B函数执 ...
1-Golang幼麟实验室笔记(切片、字符串、结构体、map)
学习前的介绍通过幼麟实验室的学习让我更加深刻的去理解Golang的底层原理,看完最深刻的感受就是脑子好痒,非常干,全是干货。自己做的笔记整理出来,方便复习和阅读。
stringUnicode字符编码变长编码
编号
编码模板
最高位固定标识位
[0, 127]
0???????
0
[128, 2047]
110????? 10??????
110 和 10
[2048, 65535]
1110???? 10?????? 10??????
1110 和 10 和 10
例如
界 编号:30028——->二进制(01110101 01001100)
将其填如对应的?位置——>得到界UTF-8编码:11100111 10010101 10001100
string的数据结构
golang不用特定标识符表示字符串的结尾。
golang采用string结构体来共同描述一个字符串。
data是指向字符串开始位置的指针。
len表示字符串的字节个数(非字符个数),因为golang采用utf8的变长编码方式,故不能采用字符个数。
string的底 ...
7-错误恢复(实现一个GoWeb框架Gee)
错误恢复目标
实现错误处理机制。
panic、defer、recoverpanic介绍:
panic 是一个 Go 内置函数,它用来停止当前常规控制流并启动 panicking(运行时恐慌)过程。当函数 F 调用 panic 函数时,函数 F 的执行停止,函数 F 中已进行了求值的 defer 函数都将得到正常执行,然后函数 F 将控制权返还给其调用者。函数 F 之后的行为就如同调用者调用的函数是 panic 一样,该 panicking(运行时恐慌)过程将继续在栈上进行下去,直到当前 goroutine 中的所有函数都返回为止,此时程序将崩溃退出。
Go 语言中,比较常见的错误处理方法是返回 error,由调用者决定后续如何处理。但是如果是无法恢复的错误,可以手动触发 panic,当然如果在程序运行过程中出现了类似于数组越界的错误,panic 也会被触发。panic 会中止当前执行的程序,退出。
主动触发panic的例子:
12345func main() { fmt.Println("before panic") panic("crash& ...
6-模板(实现一个GoWeb框架Gee)
模板目标
实现静态资源服务。
支持HTML模板渲染。
服务端渲染模板可以理解为事先定义好的HTML文档文件,模板渲染的作用机制可以简单理解为文本替换操作–使用相应的数据去替换HTML文档中事先准备好的标记。
前后端分离的开发模式:即 Web 后端提供 RESTful 接口,返回结构化的数据(通常为 JSON 或者 XML)。前端使用 AJAX 技术请求到所需的数据,利用 JavaScript 进行渲染。
前后端分离开发模式的优势:前后端解耦,前端注于界面设计实现,只需要考虑拿到数据后如何渲染即可。后端专心解决资源利用,并发,数据库等问题,只需要考虑数据如何生成。同一套后端服务能够同时支撑小程序、移动APP、PC端 Web 页面,以及对外提供的接口。
设计思路处理静态文件将所有的静态文件放在/usr/web目录下,映射到真实的文件后,将文件返回。
返回:通过net/http库解析请求的地址,映射到服务器上文件的真实地址,交给http.FileServer处理。
gee.go
Static这个方法:用户可以将磁盘上的某个文件夹root映射到路由relativePath。
12345r : ...
5-中间件(实现一个GoWeb框架Gee)
中间件目标
设计并实现 Web 框架的中间件机制。
实现通用的Logger中间件,能够记录请求到响应所花费的时间。
中间件的概念中间件,就是非业务的技术类组件。Web 框架本身不可能去理解所有的业务,因而不可能实现所有的功能。因此,框架需要有一个插口,允许用户自己定义功能,嵌入到框架中,仿佛这个功能是框架原生支持的一样。因此,对中间件而言,需要考虑2个比较关键的点:
插入点在哪?使用框架的人并不关心底层逻辑的具体实现,如果插入点太底层,中间件逻辑就会非常复杂。如果插入点离用户太近,那和用户直接定义一组函数,每次在 Handler 中手工调用没有多大的优势了。
中间件的输入是什么?中间件的输入,决定了扩展能力。暴露的参数太少,用户发挥空间有限。
那对于一个 Web 框架而言,中间件应该设计成什么样呢?接下来的实现,基本参考了 Gin 框架。
中间件设计Gee 的中间件的定义与路由映射的 Handler 一致,处理的输入是Context对象。插入点是框架接收到请求初始化Context对象后,允许用户使用自己定义的中间件做一些额外的处理,例如记录日志等,以及对Context进行二次加工 ...