简介
这是我参与「第三届青训营 -后端场」笔记创作活动的的第3篇笔记。里面介绍了GORM和其设计原理
1. 理解database/sql
基本的增删改查的几个关键词:
select delete update insert
下面是gorm获取连接的代码:
package main
import (
"fmt"
"log"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
func main() {
// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情
//获取一个连接 driver + DSN 初始化DB连接
dsn := "name:password@tcp(127.0.0.1:3306)/table?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil{
log.Fatal(err)
}
fmt.Printf("db: %v\n", db)
}
设计原理: 应用程序(上层应用) => database/sql(连接池) => 数据库,中间的sql就是数据库连接池管理,使用池化技术管理sql连接更加好,方便使用与回收,概念和java的一样。这部分和Java的JDBC有点类似,通过一个PrepareStatement来请求数据库然后返回值就返回到rows方法里面进行解析,然后就可以使用while循环读出来了
2. gorm的原理
2.1 SQL是怎么生成的
每一个sql都是由很多的子句构成的,比如一个select语句可能包含了很多的where,limit,order...那么不同的这些子句可以由很多的chain method生成,而最终有一个Finisher Method,这个用来决定执行谁。
gorm参考了sql的设计进行生成SQL语句,比如里面的一个where方法
// Where add 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
}
这里面就是把参数弄到where里面形成查询条件...具体其他方法可以看源码
这样的好处就是方便扩展以及设计比较自由,还有一个好处就是改条件的时候不需要直接修改sql语句,可以通过修改方法达到修改SQL的效果。
2.2 插件如何工作的
final Method -> 决定 statement类型 -> 执行Callbacks -> 生成SQL并执行
后面三个步骤组合起来就是插件。
预定义ceate callbacks,在调用create方法的时候就会执行事先定义好的callbacks,同时里面也提供了一些Callback供我们自定义,这样来设计,就可以自由扩展和灵活定制
- 多租户(每次都可以自动加入一个用户的id,不需要每次操作都自己手动指定)
- 多数据库、读写分离
- 加密解密
2.3 ConnPool
GORM -> ConnPool(连接池,DB Conn实现) -> 数据库
ConnPool可以分为读数据库和写数据库和事务的DB Conn, 不同的选择就基于不同的类型的Conn
全局模式下。所有DB操作都会预编译并缓存,方便后序的使用,注意缓存不会包含参数,只会包含主体sql。而会话模式下,后续会话的操作都会预编译并缓存。全局缓存的语句可以被会话使用。
实现方法就是:Prepare Stamt实现了ConnPool接口,然后去查找缓存,如果没有找到就将收到的SQL和Vars预编译,使用缓存的预编译执行。
同时这个插件也支持连接到其他国家的数据库,实现跨国的数据操作。
总结:通过这次课,大概了解了数据库的一些操作,但是具体的还是需要去看文档核录像反复学习