Gorm | 青训营笔记

84 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 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...)    }}​
  1. Builder设计模式 - 在面对复杂场景中,Builder设计模式扩展性很好,可分为两个阶段:存储数据+处理数据;GORM的调用就是采用了chainable+finisher的两段实现,前者保存SQL相关元数据,后者拼接SQL并执行;

  2. 负重前行 - GORM是一个负重前行的框架:它不仅支持了所有原生SQL的特性,也增加了很多类似Hook的高级特性,导致这个框架非常庞大。如果团队没有历史包袱,更推荐节制地使用GORM特性,适当封装一层;

  3. interface{}问题 - GORM中许多函数入参的数据类型都是interface{},底层又用reflect支持了多种类型,这种实现会导致两个问题: a. reflect导致的底层的性能不高 b. interface{}如果传入了不支持的复杂数据类型时,排查问题麻烦,往往要运行程序时才会报错

  4. 高频拼接重复SQL - 在一个程序运行过程中,执行的SQL语句都比较固定,而变化的往往是参数;从GORM的实现来看,每次执行都需要重新拼接一次SQL语句,是有不小的优化空间的,比如引入一定的cache。