使用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
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)