golang连接达梦数据库的一个坑
golanggolangodbcmssqlodbc
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("%vt", i)
		for k, v := range e {
			// 达梦数据库中文默认为gbk
			fmt.Printf("%v=%vt", 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=%vn", i, e)
	}
}

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

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

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

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

1) SQL查询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]
SELECT TOP 5 "addressid", "address1", "address2", "city", "postalcode" FROM "person.address"

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

xorm:"addressid"
engine.Table("person.address").Limit(5, 0).Find(&sliceOfAddress)
enginFind()
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()
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()enginedialectsrc.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语言中文文档