golang连接达梦数据库的一个坑
golang连接达梦数据库的一个坑
有一次项目中用到了达梦数据库,后端语言使用的golang,达梦官方并未适配专门的golang连接方式,正一筹莫展的时候发现达梦提供了odbc的连接,这样可以使用类似mssql的odbc连接方式连接达梦数据库。
使用的达梦数据库版本为DM8
达梦数据库开启odbc连接
参照上面两个博客内容配置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()的时候会解析配置信息,并赋值给engine的dialect属性,代码位置: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}
参考文档
golang连接达梦数据库的一个坑的更多相关文章
- DBeaver连接达梦数据库
1.连接类型选择ODBC. 2.编辑驱动设置: 1)Class Name:dm.jdbc.driver.DmDriver 2)URL Template:jdbc:dm://{dbserver}/{da ...
- java连接达梦数据库的简单代码
1. 引用DmJdbcDriver.jar包 2. 编写代码: String driver= "dm.jdbc.driver.DmDriver"; String url= &quo ...
- 基于Enterprise Library的Winform开发框架实现支持国产达梦数据库的扩展操作
由于一个客户朋友的需求,需要我的Winform开发框架支持国产达梦数据库的操作,这个数据库很早就听过,但是真正一般项目用的很少,一般在一些特殊的项目可能需要用到.由于我的Winform开发框架,是基于 ...
- springboot+mybatis+达梦数据库
准备工作: 首先,安装达梦6数据库.安装完之后如下建表 然后,很重要的一点(写法一定要这样写,否则无限报错) 达梦数据库查表方式: select * from "库名". ...
- ADO连接达梦7数据库,利用OLEDB建立连接
达梦数据库本身提供多种驱动如JDBC ODBC OLEDB等等 在安装的时候可以进行勾选. 如果不安装数据库的驱动无法与达梦数据库建立连接. 达梦数据库在数据库构成或结构上与oracle极为相似,而且 ...
- 国产达梦数据库的结合Enterprise Library的应用开发
在上篇<基于Enterprise Library的Winform开发框架实现支持国产达梦数据库的扩展操作>介绍了如何在Enterprise Library的数据访问层上支持这种神秘的国产数 ...
- 达梦数据库DM7小结
除了很多主流的数据库,我们很熟悉之外,越来越多的国产数据库也涌现出来. 这次就小结一些有关武汉的达梦数据库7这个开发版数据库的有别或者需要注意的地方进行一个简单备注吧. 1.第一件大事就是下载.数据库 ...
- Shell脚本使用汇总整理——达梦数据库备份脚本
Shell脚本使用汇总整理——达梦数据库备份脚本 Shell脚本使用的基本知识点汇总详情见连接: https://www.cnblogs.com/lsy-blogs/p/9223477.html 脚本 ...
- Linux平台达梦数据库V7单实例安装方式之图形方式
一 前言 我们在学习任何一个应用时,了解它的最初步骤通常是学会如何进行安装配置,后序才去关心如何使用,学习达梦数据库也是如此,而达梦数据库的安装提供了多种方式,接下来会一一介绍每种安装方式,达梦数据库 ...
随机推荐
- pipeline的使用示例
搭建就不说了,直接示例如何使用pipeline. 一.以下输入参数:版本号为字符参数,按文档更新的是文本参数. 二.脚本对更新内容的处理如下: file_update_list="/home ...
- Java基础知识面试题及答案-整理
1.String类可以被继承吗? 不能.String类在声明中使用final关键字修饰符.使用final关键字修饰的类无法被继承. Java语言的开发者为什么要将String类定义为final类呢? ...
- oracle [精华] 你是否仍迷信rowid分页?
http://www.itpub.net/thread-1603830-1-1.html
- 用jquery写一个上拉加载
/*可加载页面吗*/function canLoadMore() { return $('.loadin').length < 1;}/*移除正在加载字样*/function removeMor ...
- mysql 赋权语句
grant all privileges on phplampDB.* to phplamp@localhost identified by '1234';
- npm执行清理缓存失败npm cache clean
C:\Users\you name>npm cache cleannpm ERR! As of npm@5, the npm cache self-heals from corruption i ...
- 查看包名和Activity的小工具
添加到右键菜单,很方便. 做个记录:请移步原文
- [JavaWeb基础] 029.OGNL表达式介绍
1.OGNL概述 OGNL,全称为Object-Graph Navigation Language,它是一个功能强大的表达式语言,用来获取和设置Java对象的属性,它旨在提供一个更高的更抽象的层次来对 ...
- secureCRT连接liunx(centos6.5)系统步骤以及碰见的问题
1.首先安装secureCRT以及用vmware安装centos6.5系统,用vmware打开centos6.5系统 2.找到liunx系统的ip,在liunx终端用ifconfig找到ip如下图: ...
- 移动端适配-rem(新)
概念 对于移动端开发来说,无可避免的就是直面各种设备不同分辨率和不同DPR(设备像素比)的问题,在此忽略其他兼容性问题的探讨. 移动端像素 设备像素(dp),也叫物理像素.指设备能控制显示的最小物理单 ...