Zorm之国产化数据库实践

简介

go(golang)轻量级ORM,零依赖,支持达梦(dm),金仓(kingbase),神通(shentong),南大通用(gbase),mysql,postgresql,oracle,mssql,sqlite数据库.
源码地址:https://gitee.com/chunanyong/zorm
作者博客:https://www.jiagou.com

实践项目

夜莺监控告警项目国产化数据库的支持
夜莺是一套滴滴团队主导开源的分布式高可用的运维监控系统。
源码地址:https://github.com/didi/nightingale

改造方案

夜莺使用的是xorm作为ORM库,不支持国产数据库。尝试过通过ODBC的方式连接达梦,操作时遇到了语法不兼容问题。之后又了解到zorm,这个本身天然支持国产数据库的ORM框架。
面前出现了两种选择: 一是继续尝试ODBC的方式,一库一库的调试,手动解决各种兼容问题。二是替换项目的orm库,改造一次,就可以把国产四库的支持全部搞定。想想还是后者比较香,改造走起!

改造过程

首先数据库初始化,夜莺项目有多个数据库

//声明存储多库连接信息的map,key是dbname,value是DBDao
var DB = map[string]*zorm.DBDao{}

func InitMySQL(names ...string) {
        //读取mysql.yml数据库配置文件
    confdir := path.Join(runner.Cwd, "etc")
    mysqlYml := path.Join(confdir, "mysql.local.yml")
    if !file.IsExist(mysqlYml) {
        mysqlYml = path.Join(confdir, "mysql.yml")
    }

    confs := make(map[string]MySQLConf)
    err := file.ReadYaml(mysqlYml, &confs)
    if err != nil {
        log.Fatalf("cannot read yml[%s]: %v", mysqlYml, err)
    }
        //多库,不同的name
    count := len(names)
    for i := 0; i < count; i++ {
        conf, has := confs[names[i]]
        if !has {
            log.Fatalf("no such mysql conf: %s", names[i])
        }

        dbDaoConfig := zorm.DataSourceConfig{
            //DSN 数据库的连接字符串
            DSN: conf.Addr,
            //数据库驱动名称:mysql,postgres,oci8,sqlserver,sqlite3,dm,kingbase 和DBType对应,处理数据库有多个驱动
            DriverName: "kingbase",
            //数据库类型(方言判断依据):mysql,postgresql,oracle,mssql,sqlite,dm,kingbase 和 DriverName 对应,处理数据库有多个驱动
            DBType: "kingbase",
            //MaxOpenConns 数据库最大连接数 默认50
            MaxOpenConns: 50,
            //MaxIdleConns 数据库最大空闲连接数 默认50
            MaxIdleConns: 50,
            //ConnMaxLifetimeSecond 连接存活秒时间. 默认600(10分钟)后连接被销毁重建.避免数据库主动断开连接,造成死连接.MySQL默认wait_timeout 28800秒(8小时)
            ConnMaxLifetimeSecond: 600,
            //PrintSQL 打印SQL.会使用FuncPrintSQL记录SQL
            PrintSQL: conf.Debug,
        }
    
        // 根据dbDaoConfig创建dbDao, 一个数据库只执行一次,第一个执行的数据库为 defaultDao,后续zorm.xxx方法,默认使用的就是defaultDao
        dbDao, _ := zorm.NewDBDao(&dbDaoConfig)
        DB[names[i]] = dbDao
    }
}

建立连接
通过传入不同的dbName 获取绑定连接的Ctx

func getNewCtx(dbName string) context.Context {
    var ctx = context.Background()
    var dbDao *zorm.DBDao = DB[dbName]
        
    newCtx, err := dbDao.BindContextDBConnection(ctx)
    if err != nil { //标记测试失败
        log.Fatalf("错误:%v", err)
    }

    return newCtx
}

操作
zorm还有一个方便实用的点:

  1. 在codeGenerator.go 中配置好数据库的连接信息
  2. 如果只想初始化单张表,请修改codeGenerator_test.go 中TestCodeGenerator调用的code参数,为表名
  3. 单表初始化:执行go test -v codeGenerator_test.go codeGenerator.go -test.run TestCodeGenerator
    整个库初始化:执行go test -v codeGenerator_test.go codeGenerator.go -test.run TestCodeGeneratorALL

生成器代码简单清晰,可根据自己的需求做一些调整,使最终生成的代码能一步到位。

生成效果
拿一个表举例

//table name
const NodeStructTableName = "node"

// NodeStruct
type Node struct {
    zorm.EntityStruct
    Id int64 `column:"id" json:"id"`
    Pid int64 `column:"pid" json:"pid"`
    Name string `column:"name" json:"name"`
    Path string `column:"path" json:"path"`
    Leaf int `column:"leaf" json:"leaf"`
    Note string `column:"note" json:"note"`

}

func (entity *Node) GetTableName() string {
    return NodeStructTableName
}

//GetPKColumnName 获取数据库表的主键字段名称.因为要兼容Map,只能是数据库的字段名称.
func (entity *Node) GetPKColumnName() string {
    return "id"
}

增删改查
使用原生的sql语句,没有对sql语法做限制.语句使用Finder作为载体

    //查询
    var obj Node
    //has, err := DB["mon"].Where(col+"=?", val).Get(&obj)  这是之前xorm的代码
    //获取对应数据库的连接
    newCtx := getNewCtx("mon")
    finder := zorm.NewSelectFinder(NodeStructTableName) 
    finder.Append("WHERE "+col+"=?", val)
    has, err := zorm.QueryRow(newCtx, finder, &obj)



  //添加
    node := Node{
        Pid:  0,
        Name: "cop",
        Path: "cop",
        Leaf: 0,
        Note: "公司节点",
    }
    //_, err = DB["mon"].Insert(&node)  这是之前xorm的代码
    //手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
    _, err = zorm.Transaction(newCtx, func(newCtx context.Context) (interface{}, error) {
        //具体操作
        _, err = zorm.Insert(newCtx, &node)
        return nil, err
    })
    
    if err != nil {
        log.Fatalln("cannot insert node[cop]")
    }


    //修改
    newCtx := getNewCtx("mon")
    //手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
    _, err := zorm.Transaction(newCtx, func(newCtx context.Context) (interface{}, error) {
        _, err := zorm.Update(newCtx, obj)
        //如果返回的err不是nil,事务就会回滚
        return nil, err

    })
      

    //删除
    //_, err := DB["mon"].Where("id=?", n.Id).Delete(new(Node))
    //手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
    _, err := zorm.Transaction(newCtx, func(newCtx context.Context) (interface{}, error) {
        finder := zorm.NewDeleteFinder(NodeStructTableName)
        finder.Append("WHERE id=?", n.Id)
        _, err := zorm.UpdateFinder(newCtx, finder)
        return nil, err
    })

改造总结

zorm上手非常简单,改造过程也很顺畅。
以上只是zorm使用的部分示例,除此之外zorm还支持事务传播、批量操作、不方便使用struct的场景,以及读写分离等。更多使用场景请前往 zorm官方
如有使用方面的疑问请下方留言,改造建议或想了解更多,请在最上方源码地址找官方,作者回复也很热情: )

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容