beego-ORM 适配达梦

麒麟&达梦适配系列:

1.麒麟服务器上安装 DM8
2.配置 UnixODBC
3.beego-ORM 适配达梦



在选型设计的时候,主要考虑了以下几种 ORM:

ORM 名称 可行性 优势 劣势 说明
oci8 不可行 因为 DM 和 oracle 很像,所以尝试使用 oci 对接

测试时候发现发现:Open连接没有问题,但是Query的时候会报 Lost Connection

经在官网查询,及和达梦同学确认,发现这确实是不可行的死路
XORM 可行 好对接 内部没有使用经验
星少(6.2k)
未进行对接尝试
GORM@V1.0 可行 好对接
内部使用广泛
不再新增feature(已和作者确认) 进行过对接尝试:ORM 和 Raw SQL 均可行
GORM@V2.0 可行 星多(21.9k)
GORM@V1.0迁移过去的,质量有保障
内部同学曾尝试升级,单测不过,暂时搁置 未进行对接尝试
beego ORM 可行 星多(25.5k)
内部有使用经验
对接完成


因为我们打头阵,要和 DM 对接的项目本身用的是 beego ORM,所以 beego ORM 也是我们最终的选用方案。

项目已计划开源,请关注后续更新

项目本身使用的 DB 是 MySQL。所以,除了需要对接 ODBC 这种新驱动方式外,还需要做一些定制化的处理,来保障项目使用平滑:

1 自增 ID 的处理

MySQL 指定自增的方式是: AUTO_INCREMENT

DM 指定自增的方式是: IDENTITY

区别于 AUTO_INCREMENT 的可指定(insert)可修改(update),IDENTITY 默认是不可指定的,更不可修改。

使用 SET IDENTITY_INSERT SCHEMA.TABLE ON 命令,可以使得 在 insert 时指定自增列的值 (仅对当前连接生效)。

但是,没有命令可以实现:update 自增列,只能通过 delete + insert 方式绕过这个问题。



2 对于获取LastInsertID的处理

在原始项目中,我们使用 orm.Insert 来实现单条数据的插入,并获得返回值 LastInsertID 来做后续处理。

而我们使用的适配 DM8 的 odbc pkg 没有实现这部分功能,调用即报错。源码如下:

func (r *Result) LastInsertID() (int64, error) {
    // TODO(brainman): implement (*Result).LastInsertID
    return 0, errors.New("not implemented")
}

经过对 cgo 代码的分析,发现确实没有现成的变量可以实现这个功能。经查询文档,发现可以使用 SELECT SCOPE_IDENTITY() 来做封装实现:

func lastInsertID(q dbQuerier, mi *modelInfo) (lastInsertID int64, err error) {

    if &mi.fields.pk == nil {
        return
    }
    lidQuery := fmt.Sprintf("SELECT SCOPE_IDENTITY()")
    lid, err := q.Query(lidQuery)
    for lid.Next() {
        err = lid.Scan(&lastInsertID)
        if err != nil {
            return
        }
    }
    return
}




3 多种 insert 方式支持

beego ORM 实现了多种 insert 方式,我们用到的有 3 种:

  1. insert
  2. prepare insert
  3. multi-insert

其中,multi-insert 指的是这种:insert into tbl () values (),(),()...();

对于此种方式,ORM 默认返回影响行数,计算方式如下:

var sumRowCount int64
for {
    var c api.SQLLEN
    ret := api.SQLRowCount(s.os.h, &c)
    if IsError(ret) {
        return nil, NewError("SQLRowCount", s.os.h)
    }
    sumRowCount += int64(c)
    if ret = api.SQLMoreResults(s.os.h); ret == api.SQL_NO_DATA {
        break
    }
}

对于 insertprepare insert,ORM 返回 LastInsertID,获得方式见:“ 2 对于获取LastInsertID的处理 ”

说明:

  • 我们使用 prepare insert 是为了提高插入效率,而通过上述封装方式去获得 LastInsertID,相当于是 double 了交互,于是在此暂不进行上述方法的调用
  • insert 时正常调用该方法,获取 LastInsertID



4 大小写的问题

在大小写不敏感的环境下,MySQL 会默认将表名、列名等相关字符转化为小写。

而 DM 会将相关字符转化为大写。

解决办法:定义结构体时,做 column 指定,避免渲染出错。

示例:

type TblTest struct {
    Id             uint32 `orm:"column(ID)";pk`
    NameTest       uint32 `orm:"column(NAME_TEST);sequence(PK_APP)"`
    ...
}

func (t *TblTest) TableName() string {
    return "TBL_TEST"
}

说明:sequence 是为适配 DM 序列使用,封装的新 tag,详见开源代码。



5 反引号的使用

在 MySQL 中,常使用反引号 `` 来扩起表名和列名,避免因使用关键字定义了表或列,影响到使用。

但是 DM,它是不能解析反引号的,所以我们改用双引号扩起表名和列名。



6 用户和模式

区别于 MySQL,DM 的模式是创建在用户下的,一个用户可以拥有多个模式。

创建用户时,会默认创建同名模式。模式一经建成,无法修改所属用户。建议大家直接创建同名账号,进行对应的模式使用,而非反其道而行之。



7 语法差别

这里拿 MySQL 为例,与 DM8 语法做个类比:

MySQL DM8




8 系统表差别

这里拿 MySQL 为例,与 DM8 系统表做个类比:

MySQL DM8



因为 DM 是没办法在 MacOS 环境编译的,而 UnixODBC 又必须引用 DM 的 .so 文件,所以选择将 UnixODBC 部署在 arm 架构的 docker 中。

最终的结构示意图:

DM8 结构图.jpg

我个人是试用 GoLand + dlv 做远程调试的,配置方式参考:goland远程调试

注意:远程和本地项目路径必须一致,不然断点会调到莫名的位置


本文章为麒麟&达梦适配系列第三篇。

上一篇:配置 UnixODBC

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