美文网首页
2019-09-09, beego代码走读,五、ORM

2019-09-09, beego代码走读,五、ORM

作者: onmeiei | 来源:发表于2019-09-29 20:06 被阅读0次

    先贴一段README中的使用示例,很像JAVA的JPA的操作,算是致敬了吧?。

    func init() {
        // register model
        orm.RegisterModel(new(User))
    
        // set default database
        orm.RegisterDataBase("default", "mysql", "root:root@/my_db?charset=utf8", 30)
        
        // create table
        orm.RunSyncdb("default", false, true)   
    }
    
    func main() {
        o := orm.NewOrm()
    
        user := User{Name: "slene"}
    
        // insert
        id, err := o.Insert(&user)
    
        // update
        user.Name = "astaxie"
        num, err := o.Update(&user)
    
        // read one
        u := User{Id: user.Id}
        err = o.Read(&u)
    
        // delete
        num, err = o.Delete(&u) 
    }
    

    先看一下Init中的方法RegisterModelRegisterDataBaseRunSyncdb

    RegisterModel

    func registerModel(PrefixOrSuffix string, model interface{}, isPrefix bool) {
        //反射获得类型,通过这两步操作,就可以获得了model interface{}实际上的类型。
        val := reflect.ValueOf(model)
        typ := reflect.Indirect(val).Type()
        //省略。。。
    }
    

    通过反射获取到interface{}的类型之后,可以通过类型获得Table的名称。
    首先,尝试通过TableName方法获取;如果失败,则使用Type().Name()作为名称。

    func getTableName(val reflect.Value) string {
        if fun := val.MethodByName("TableName"); fun.IsValid() {
            vals := fun.Call([]reflect.Value{})
            // has return and the first val is string
            if len(vals) > 0 && vals[0].Kind() == reflect.String {
                return vals[0].String()
            }
        }
        return snakeString(reflect.Indirect(val).Type().Name())
    }
    

    然后再调用newModelInfo, 调用addModelFields,通过反射获取到model所有的Fields映射为数据库的Column(画外音:如果有类似Java的Annotation,就会方便很多了)。

    最后,将生成的Model放入Cache

    modelCache.set(table, mi)
    

    RegisterDataBase

    Q: DataBase还是Database,哪个才是正确的名字呢?(*——*)

    db, err = sql.Open(driverName, dataSource)
    

    和JDBC的操作很类似,通过driverName打开数据库连接,类似于SPI的操作。

    题外话
    目前golang直连的数据库驱动很是贫乏,如果做企业级应用的话,还是用Java吧。
    avelino/awesome-go 中列举的很多的数据库驱动。例如,Oracle(OCI)这个很复杂。

    将数据库连接池进行缓存,将sql/DB对象缓存到dataBaseCache对象中

     addAliasWthDB(aliasName, driverName, db)
    

    检测数据库的时区设置,用于后续的Model中的timestamp类型保存和读取。

    detectTZ(al)
    

    设置连接数;我看了下golang SDK中sql/DB支持的设置,还支持超时时间。

    SetMaxIdleConns(al.Name, v)
    SetMaxOpenConns(al.Name, v)
    
    sql/DB

    满足了最基本的数据库连接池的基本素质。

    做为比对,感受一下Java生态中的当红辣子鸡Hikari的连接池设置,满满一屏幕的set方法。

    Hikari

    RunSyncdb

    这个没什么特别需要说的内容,就是fmt.Sprintf拼接SQL字符串。

    接下来,看一下main中的几个操作,NewOrm,Insert,Update,Read,Delete

    NewOrm

    NewOrm会首次调用Bootstrap来初始化Model的关联关系,包括OneToOne、OneToMany等等。

    const (
        RelForeignKey
        RelOneToOne
        RelManyToMany
        RelReverseOne
        RelReverseMany
    )
    

    Bootstrap方法大篇幅的代码都是在构建Model的关系信息。参考下图:
    代码繁琐,但是很容易理解,就不逐行分析了。

    orm/models_boot.go:93

    Bootstrap执行完毕之后,会调用一个Using方法,Using("default")Using方法的核心是从缓存中找到连接池。

    if al, ok := dataBaseCache.get(name); ok {
    }
    

    dataBaseCache在RegisterDataBase方法中进行了初始化。

    相关文章

      网友评论

          本文标题:2019-09-09, beego代码走读,五、ORM

          本文链接:https://www.haomeiwen.com/subject/eyimyctx.html