达梦数据库如何连接MySQL_golang连接达梦数据库的一个坑

本文介绍了如何使用Go语言通过ODBC驱动连接达梦数据库,详细解析了遇到的陷阱,包括解决Go包下载问题、表名错误及去除SQL中的双引号,提供了解决方案和代码示例。
摘要由CSDN通过智能技术生成

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/ 下包下载不下来的问题

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中执行是没问题的,但是放到达梦数据库中就会报错,因为达梦不支持双引号包裹字段、命名空间、表名:

064959c31c60b83bea76eea3dc59d16f.png

这样就很坑爹了,我尝试着修改结构体的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之后去掉双引号即可,因为做了判断只有是达梦的类型数据库的时候才修改,所以不会影响其他类型的数据库。至此问题得到了解决。

解决方式二)

上面的方式一是一种解决方案,其实有更简便的,因为我们在创建engine的时候已经确定了dialect类型为dialect_mssql,找到src.github.com/go-xorm/xorm/dialect_mssql.go找到方法Quote稍作修改即可:

func (db *mssql) Quote(name string) string {

fmt.Println("Quote -> ", db.URI().DbName) // DM

if db.URI().DbName == "DM" { // 如果是达梦数据库不添加双引号

return name

}

return "\"" + name + "\""

}

这样,是在拼接SQL之前修改了逻辑,二方式一是在拼接之后再去掉引号,方式二更方便一点。

注意:

查阅最新的文档,发现最新的xorm.io/core v1.0.1版本已经支持使用engine.Dialect().SetQuotePolicy(core.QuotePolicyNone)来设置引号策略。如果你使用的是该版本,直接设置即可。

Dialect结构体、QuotePolicy常量值

输出结果:

[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}

参考文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值