这是我参与「第五届青训营 」伴学笔记创作活动的第 11 天
gorm
orm是object relational mapping的缩写,意思就是对象映射关系,一般我们使用的java、python什么的都是面向对象开发,但是数据库一般是关系型,为了保持开发一致的习惯,orm就把编程语言的对象模型和数据库的关系模型建立了映射关系,这样就可以不用直接使用sql而使用对象模型就可以对数据库进行操作了
gorm是一个对go开发者友好的orm库,有很多功能,几乎包含所有orm特性
// 查询所有对象var users []User result := db.Find(&users)// 指定查询条件(where) 这里的name和Age:指定查询传入结构体中的哪些字段db.Where(&User{Name: "jinzhu"}, "name", "Age").Find(&users)// 限制返回数量db.Limit(10).Offset(5).Find(&users)// 查询部分字段(即从select * 改造为 select name, age)db.Select("name", "age").Find(&users)// 其余扩展db.Order("age desc, name").Find(&users)
核心-构建SQL的实现
func BuildQuerySQL(db *gorm.DB) { // SQL为空,表示需要自己构建 if db.Statement.SQL.String() == "" { db.Statement.SQL.Grow(100) // 分配初始空间 if len(db.Statement.Selects) > 0 { // 表示只select某几个字段,而不是select * } else if db.Statement.Schema != nil && len(db.Statement.Omits) > 0 { // Omit表示忽略特定字段 } else if db.Statement.Schema != nil && db.Statement.ReflectValue.IsValid() { // 查询到指定结构体 } // 对join的处理,涉及到多表关联,暂时忽略 if len(db.Statement.Joins) != 0 { } else { db.Statement.AddClauseIfNotExists(clause.From{}) } // 用一个map去重,符合名字中的 IfNotExists 含义 db.Statement.AddClauseIfNotExists(clauseSelect) // 最后拼接出完整 SQL 的地方 db.Statement.Build(db.Statement.BuildClauses...) }}
-
Builder设计模式 - 在面对复杂场景中,Builder设计模式扩展性很好,可分为两个阶段:存储数据+处理数据;GORM的调用就是采用了chainable+finisher的两段实现,前者保存SQL相关元数据,后者拼接SQL并执行;
-
负重前行 - GORM是一个负重前行的框架:它不仅支持了所有原生SQL的特性,也增加了很多类似Hook的高级特性,导致这个框架非常庞大。如果团队没有历史包袱,更推荐节制地使用GORM特性,适当封装一层;
-
interface{}问题 - GORM中许多函数入参的数据类型都是interface{},底层又用reflect支持了多种类型,这种实现会导致两个问题: a. reflect导致的底层的性能不高 b. interface{}如果传入了不支持的复杂数据类型时,排查问题麻烦,往往要运行程序时才会报错
-
高频拼接重复SQL - 在一个程序运行过程中,执行的SQL语句都比较固定,而变化的往往是参数;从GORM的实现来看,每次执行都需要重新拼接一次SQL语句,是有不小的优化空间的,比如引入一定的cache。