GORM记录-1 | 青训营笔记

135 阅读3分钟

简介

这是我参与「第三届青训营 -后端场」笔记创作活动的的第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预编译,使用缓存的预编译执行。

同时这个插件也支持连接到其他国家的数据库,实现跨国的数据操作。



总结:通过这次课,大概了解了数据库的一些操作,但是具体的还是需要去看文档核录像反复学习