zorm 达梦适配问题

zorm 达梦适配问题,第1张

使用zorm适配达梦数据库

驱动程序问题

安装

go get gitee.com/chunanyong/dm

配置驱动


import (
	"fmt"
	_ "gitee.com/chunanyong/dm"
	"gitee.com/chunanyong/zorm"
	"strings"

)

// Conn MySQL数据库连接
func Conn(username, password, addr string) (*zorm.DBDao, error) {
	dsn := fmt.Sprintf("dm://%s:%s@%s/%s", username, password, addr, strings.ToUpper(entity.DBName))
	dbConfig := &zorm.DataSourceConfig{
		DSN:        dsn,
		DriverName: "dm",
		DBType:     "dm",
		PrintSQL:   true,
	}
	return zorm.NewDBDao(dbConfig)
}

TEXT字段映射问题

没有添加映射前,DM的TEXT驱动映射为dm.DmClob,无法转换为golang string类型,出现查询出来的字段为空的问题,如下:

QueryRow-->sqlRowsValues错误:sql: 

Scan error on column index 10, name "CONTENT": unsupported Scan,
storing driver.Value type *dm.DmClob into type *string

该问题可以通过使用手动指定的类型映射来自己解析,参考 zorm官方示例: structFieldInfo.go

要注意,示例中的代码没有处理 字段为 ""(空串)或 NULL的场合需要手段判断EOF然后处理,完整代码如下:

import (
	"database/sql"
	"database/sql/driver"
	"fmt"
	"gitee.com/chunanyong/dm"
	"gitee.com/chunanyong/zorm"
	"io"
	"reflect"
	"strconv"
)

// CustomDMText 实现CustomDriverValueConver接口
// 解决:达梦数据库text类型,映射出来的是dm.DmClob类型,无法使用string类型直接接收
type CustomDMText struct{}

// GetDriverValue 根据数据库列类型,实体类属性类型,Finder对象,返回driver.Value的实例
// 如果无法获取到structFieldType,例如Map查询,会传入nil
// 如果返回值为nil,接口扩展逻辑无效,使用原生的方式接收数据库字段值
func (dmtext *CustomDMText) GetDriverValue(_ *sql.ColumnType, _ *reflect.Type, _ *zorm.Finder) (driver.Value, error) {
	return &dm.DmClob{}, nil
}

// ConverDriverValue 数据库列类型,实体类属性类型,GetDriverValue返回的driver.Value的临时接收值,Finder对象
// 如果无法获取到structFieldType,例如Map查询,会传入nil
// 返回符合接收类型值的指针,指针,指针!!!!
func (dmtext *CustomDMText) ConverDriverValue(_ *sql.ColumnType, _ *reflect.Type, tempDriverValue driver.Value, _ *zorm.Finder) (interface{}, error) {
	//类型转换
	dmClob, isok := tempDriverValue.(*dm.DmClob)
	if !isok {
		return tempDriverValue, fmt.Errorf("转换至*dm.DmClob类型失败")
	}

	//获取长度
	dmlen, errLength := dmClob.GetLength()
	if errLength != nil {
		return dmClob, errLength
	}

	//int64转成int类型
	strInt64 := strconv.FormatInt(dmlen, 10)
	dmlenInt, errAtoi := strconv.Atoi(strInt64)
	if errAtoi != nil {
		return dmClob, errAtoi
	}

	//读取字符串
	str, errReadString := dmClob.ReadString(1, dmlenInt)
	// 手动处理空串,防止EOF造成的异常导致字段解析失败。
	if errReadString == io.EOF {
		return &str, nil
	}
	return &str, errReadString
}

更新/删除 2002错误码

使用如下语句对表进行更新

// Set 设置单个参数值
func Set(ctx context.Context, key string, value interface{}) error {
	finder := zorm.NewUpdateFinder(entity.ConfigTableName)
	finder.Append("content=?", fmt.Sprintf("%v", value))
	finder.Append("WHERE item_name=?", key)
	_, err := zorm.QueryRow(ctx, finder, &entity.Config{})
	return err
}

上述代码在MYSQL下运行是没有任何问题,在DM环境就会发生 错误码:2002 ,panic如下:

该问题由于 UPDATE、DELETE语句不会返回查询结果集,返回的结果只是一个受影响行数,在查询时

_, err := zorm.QueryRow(ctx, finder, &entity.Config{})

我们传入了一个实体的指针,这里在返回的结果集解析映射时发生了错误。

解决方案1

使用 int 作为接收参数就可以解决该问题

// Set 设置单个参数值
func Set(ctx context.Context, key string, value interface{}) error {
	finder := zorm.NewUpdateFinder(entity.ConfigTableName)
	finder.Append("content=?", fmt.Sprintf("%v", value))
	finder.Append("WHERE item_name=?", key)
	effect := 0
	_, err := zorm.QueryRow(ctx, finder, &effect)
	return err
}
解决方案2

直接使用zorm.UpdateFinder替换更新语句,但是zorm没有针对批量删除写响应的方法,因此还是需要采用方案1。

func Set(ctx context.Context, key string, value interface{}) error {
	finder := zorm.NewUpdateFinder(entity.ConfigTableName)
	finder.Append("content=?", fmt.Sprintf("%v", value))
	finder.Append("WHERE item_name=?", key)
	effect := 0
	_, err := zorm.UpdateFinder(ctx, finder)
	return err
}
参考文献

[1]. gitee . zorm . springrain . 2022 . https://gitee.com/chunanyong/zorm

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/996095.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存