golang连接达梦数据库的一个坑

有一次项目中用到了达梦数据库,后端语言使用的golang,达梦官方并未适配专门的golang连接方式,正一筹莫展的时候发现达梦提供了odbc的连接,这样可以使用类似mssqlodbc连接方式连接达梦数据库。

使用的达梦数据库版本为DM8

达梦数据库开启odbc连接

参考博客1参考博客2

参照上面两个博客内容配置odbc连接

golang代码

一些参考文档:

package main
import (
"fmt"
_ "github.com/alexbrainman/odbc" // google's odbc driver
"github.com/go-xorm/xorm"
"xorm.io/core"
"github.com/axgle/mahonia"
) type Address struct {
Addressid int64 `xorm:"addressid"`
Address1 string `xorm:"address1"`
Address2 string `xorm:"address2"`
City string `xorm:"city"`
Postalcode string `xorm:"postalcode"`
} // 字符串解码函数,处理中文乱码
func ConvertToString(src string, srcCode string, tagCode string) string {
srcCoder := mahonia.NewDecoder(srcCode)
srcResult := srcCoder.ConvertString(src)
tagCoder := mahonia.NewDecoder(tagCode)
_, cdata, _ := tagCoder.Translate([]byte(srcResult), true)
result := string(cdata)
return result
} func main() {
engine, err := xorm.NewEngine("odbc", "driver={DM8 ODBC DRIVER};server=127.0.0.1:5236;database=DM;uid=SYSDBA;pwd=password;charset=utf8")
if err != nil {
fmt.Println("new engine got error:", err)
return
}
engine.ShowSQL(true)//控制台打印出生成的SQL语句;
engine.Logger().SetLevel(core.LOG_DEBUG)
if err := engine.Ping(); err != nil {
fmt.Println("ping got error:", err)
return
} // 1) sql查询
results, err := engine.Query("select addressid, address1, address2, city, postalcode from person.address limit 5 offset 2")
if err != nil {
fmt.Println("查询出错:", err)
return
}
for i, e := range results {
fmt.Printf("%v\t", i)
for k, v := range e {
// 达梦数据库中文默认为gbk
fmt.Printf("%v=%v\t", k, ConvertToString(string(v), "gbk", "utf-8"))
}
fmt.Printf("\n")
}
fmt.Println("*******************************")
// 2) 使用struct 映射结果
engine.SetMapper(core.SameMapper{})
var sliceOfAddress []Address
err = engine.Table("person.address").Limit(5, 0).Find(&sliceOfAddress)
if err != nil {
fmt.Println("查询出错:", err)
return
}
for i,e := range sliceOfAddress {
e.Address1 = ConvertToString(e.Address1, "gbk", "utf-8")
e.Address2 = ConvertToString(e.Address2, "gbk", "utf-8")
e.City = ConvertToString(e.City, "gbk", "utf-8")
fmt.Printf("%v=%v\n", i, e)
}
}

1)解决 golang.org/x/ 下包下载不下来的问题

https://studygolang.com/articles/19051?fr=sidebar

https://studygolang.com/articles/24075?fr=sidebar

2)无效的表或视图名[person.address](这个也是最坑的一点)

原因:我们使用的是odbc的方式连接达梦数据库,实际上使用的是mssql的驱动,第一个1) SQL查询结果是OK的,但是2) struct 查询就会报错:

[xorm] [info]  2020/06/08 16:52:40.183731 [SQL] SELECT TOP 5 "addressid", "address1", "address2", "city", "postalcode" FROM "person.address"
查询出错: SQLPrepare: {42S02} 第1 行附近出现错误:
无效的表或视图名[person.address]

通过日志发现,xorm吧没一个字段和表名都添加上了双引号:SELECT TOP 5 "addressid", "address1", "address2", "city", "postalcode" FROM "person.address"这个sql在mssql中执行是没问题的,但是放到达梦数据库中就会报错,因为达梦不支持双引号包裹字段、命名空间、表名:

这样就很坑爹了,我尝试着修改结构体的xorm:"addressid"去掉其中的双引号,但是问题还存在,最后想到打印出来的sql中待了双引号,说明xorm后台还是拼接的sql语句,如果找到拼接sql语句的代码然后去掉其中的双引号不是就好了么。于是跟踪代码查找拼接sql的代码:

1、engine.Table("person.address").Limit(5, 0).Find(&sliceOfAddress)

先找到engin模块的Find()方法:

代码路径:src.github.com/go-xorm/xorm/engine.go

// Find retrieve records from table, condiBeans's non-empty fields
// are conditions. beans could be []Struct, []*Struct, map[int64]Struct
// map[int64]*Struct
func (engine *Engine) Find(beans interface{}, condiBeans ...interface{}) error {
session := engine.NewSession()
defer session.Close()
return session.Find(beans, condiBeans...)
}

发现其实调用的是session.Find() 方法

2、src.github.com/go-xorm/session_find.go

// Find retrieve records from table, condiBeans's non-empty fields
// are conditions. beans could be []Struct, []*Struct, map[int64]Struct
// map[int64]*Struct
func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
if session.isAutoClose {
defer session.Close()
}
return session.find(rowsSlicePtr, condiBean...)
}

发现实际上调用的是session.find(rowsSlicePtr, condiBean...)

func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{}) error {

	defer session.resetStatement()

	// 代码省略 。。。

	var sqlStr string
var args []interface{}
var err error
// 此处就是拼接sql的代码
if session.statement.RawSQL == "" {
// 代码省略 。。。
} else {
sqlStr = session.statement.RawSQL
args = session.statement.RawParams
}
// 获得配置信息判断当前数据库类型
uri := session.engine.Dialect().URI()
// 判断当前是否是达梦数据库
if uri.DbType == "mssql" && uri.DbName == "DM" {
newSqlStr := strings.Replace(sqlStr, "\"", "", -1) // 去掉双引号
sqlStr = newSqlStr
} // 代码省略 。。。
return session.noCacheFind(table, sliceValue, sqlStr, args...)
}

通过session.engine.Dialect().URI()获得配置信息,这段代码怎么来的,实际上是在xorm.NewEngine()的时候会解析配置信息,并赋值给enginedialect属性,代码位置:src.github.com/go-xorm/xorm/xorm.go

engine := &Engine{
db: db,
dialect: dialect,
Tables: make(map[reflect.Type]*core.Table),
mutex: &sync.RWMutex{},
TagIdentifier: "xorm",
TZLocation: time.Local,
tagHandlers: defaultTagHandlers,
cachers: make(map[string]core.Cacher),
defaultContext: context.Background(),
}

找到sql之后去掉双引号即可,因为做了判断只有是达梦的类型数据库的时候才修改,所以不会影响其他类型的数据库。至此问题得到了解决。

输出结果:

[xorm] [info]  2020/06/08 17:14:18.061667 PING DATABASE odbc
[xorm] [info] 2020/06/08 17:14:19.315349 [SQL] select addressid, address1, address2, city, postalcode from person.address limit 5 offset 2
0 ADDRESSID=3 ADDRESS1=青山区青翠苑1号 ADDRESS2= CITY=武汉市青山区 POSTALCODE=430080
1 ADDRESSID=4 ADDRESS1=武昌区武船新村115号 ADDRESS2= CITY=武汉市武昌区 POSTALCODE=430063
2 ADDRESSID=5 ADDRESS1=汉阳大道熊家湾15号 ADDRESS2= CITY=武汉市汉阳区 POSTALCODE=430050
3 ADDRESSID=6 ADDRESS1=洪山区保利花园50-1-304 ADDRESS2= CITY=武汉市洪山区 POSTALCODE=430073
4 ADDRESSID=7 ADDRESS1=洪山区保利花园51-1-702 ADDRESS2= CITY=武汉市洪山区 POSTALCODE=430073
*******************************
[xorm] [info] 2020/06/08 17:14:19.324291 [SQL] SELECT TOP 5 addressid, address1, address2, city, postalcode FROM person.address
0={1 洪山区369号金地太阳城56-1-202 武汉市洪山区 430073}
1={2 洪山区369号金地太阳城57-2-302 武汉市洪山区 430073}
2={3 青山区青翠苑1号 武汉市青山区 430080}
3={4 武昌区武船新村115号 武汉市武昌区 430063}
4={5 汉阳大道熊家湾15号 武汉市汉阳区 430050}

参考文档

xorm的操作指南

xorm的pkg文档

go语言中文文档

golang连接达梦数据库的一个坑的更多相关文章

  1. DBeaver连接达梦数据库

    1.连接类型选择ODBC. 2.编辑驱动设置: 1)Class Name:dm.jdbc.driver.DmDriver 2)URL Template:jdbc:dm://{dbserver}/{da ...

  2. java连接达梦数据库的简单代码

    1. 引用DmJdbcDriver.jar包 2. 编写代码: String driver= "dm.jdbc.driver.DmDriver"; String url= &quo ...

  3. 基于Enterprise Library的Winform开发框架实现支持国产达梦数据库的扩展操作

    由于一个客户朋友的需求,需要我的Winform开发框架支持国产达梦数据库的操作,这个数据库很早就听过,但是真正一般项目用的很少,一般在一些特殊的项目可能需要用到.由于我的Winform开发框架,是基于 ...

  4. springboot+mybatis+达梦数据库

    准备工作: 首先,安装达梦6数据库.安装完之后如下建表 然后,很重要的一点(写法一定要这样写,否则无限报错) 达梦数据库查表方式: select  *  from    "库名". ...

  5. ADO连接达梦7数据库,利用OLEDB建立连接

    达梦数据库本身提供多种驱动如JDBC ODBC OLEDB等等 在安装的时候可以进行勾选. 如果不安装数据库的驱动无法与达梦数据库建立连接. 达梦数据库在数据库构成或结构上与oracle极为相似,而且 ...

  6. 国产达梦数据库的结合Enterprise Library的应用开发

    在上篇<基于Enterprise Library的Winform开发框架实现支持国产达梦数据库的扩展操作>介绍了如何在Enterprise Library的数据访问层上支持这种神秘的国产数 ...

  7. 达梦数据库DM7小结

    除了很多主流的数据库,我们很熟悉之外,越来越多的国产数据库也涌现出来. 这次就小结一些有关武汉的达梦数据库7这个开发版数据库的有别或者需要注意的地方进行一个简单备注吧. 1.第一件大事就是下载.数据库 ...

  8. Shell脚本使用汇总整理——达梦数据库备份脚本

    Shell脚本使用汇总整理——达梦数据库备份脚本 Shell脚本使用的基本知识点汇总详情见连接: https://www.cnblogs.com/lsy-blogs/p/9223477.html 脚本 ...

  9. Linux平台达梦数据库V7单实例安装方式之图形方式

    一 前言 我们在学习任何一个应用时,了解它的最初步骤通常是学会如何进行安装配置,后序才去关心如何使用,学习达梦数据库也是如此,而达梦数据库的安装提供了多种方式,接下来会一一介绍每种安装方式,达梦数据库 ...

随机推荐

  1. new和alloc的区别

    简单来说,new和alloc在功能上基本没有什么区别,都是分配内存,初始化对象. 但是,调用new的话,只能通过默认的init方法来初始化对象,而alloc可以通过其他的初始化方法如:-(instan ...

  2. redis的相关知识

    1. 依赖包安装 pom.xml 加入: <!-- redis cache related.....start --> <dependency> <groupId> ...

  3. 01.Net入门知识

    1..Net学习路线及几个容易混淆的概念 .Net只是一个平台,提供运行.Net程序需要的虚拟机.类库等 C#就是.Net平台下的一个开发语言,.Net下的语言还有VB.Net.PowerShell等 ...

  4. 浅论ajax跨域!从一个例子开始!

    //所谓跨域,简单来说就是去访问不是自己域名下的数据 <!DOCTYPE html> <html lang="en"> <head> <m ...

  5. hdu-4080 Stammering Aliens 字符串hash 模板题

    http://acm.hdu.edu.cn/showproblem.php?pid=4080 求出现次数大于等于n的最长串. #include<iostream> #include< ...

  6. jenkins-node-pipeline

    Jenkins node创建 1.jenkins搭建参考我的另外一篇文章:    http://www.cnblogs.com/cuishuai/p/7544775.html 2.搭建完成后登录,选择 ...

  7. jenkins定时构建

    打开job的配置界面,在构建触发器栏下有Poll SCM(定时检查源码变更并构建)和Build periodically(周期进行项目构建,不关心源码是否变更) 定时构建语法: * * * * *(和 ...

  8. 团队作业:第五周 Alpha版本测试与发布

    团队:你吼辣么大声干什么嘛 Alpha版本测试报告:    bug: 修复的bug:     不能重现的bug:  无 产品设计,非bug: 在双人对战模式中,撞到墙壁会从对面的墙壁穿出,不会死 没能 ...

  9. 回溯法之k着色问题

    package main import ( "fmt" ) type Graphic struct { edges [][]int colors int color []int f ...

  10. 2890: C--去掉+86

    2890: C--去掉+86 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 210  Solved: 91[Submit][Status][Web Bo ...