go redis 获取数据时Scan失败 提示redis: can‘t unmarshal %T (consider implementing BinaryUnmarshaler) 解决方法
如果存储的是自定义结构体, 在使用Scan获取数据的时候,则必须要实现 encoding.BinaryUnmarshaler 这个接口,否则Scan无法获取数据。实现解码接口很简单,实际上就是在你的对象上面增加一个UnmarshalBinary方法,当你在调用go-redis的scan的时候他就会自动调用你的自定义对象中的UnmarshalBinary方法,从而你就可以获取到你要的数据了。方法定义
原因
go-redis 在存储对象数据后,无法通过Scan获取, 这个原因是go-redis对你要Scan的数据类型不支持, 他只支持基本数据类型,time类型包含Duration,*net.IP类型和 实现了go内置encoding包中的BinaryUnmarshaler接口的对象类型。
解决方法
自定义结构体类型数据获取
如果存储的是自定义结构体, 在使用Scan获取数据的时候,则必须要实现 encoding.BinaryUnmarshaler 这个接口,否则Scan无法获取数据。 实现解码接口很简单,实际上就是在你的对象上面增加一个UnmarshalBinary方法,当你在调用go-redis的scan的时候他就会自动调用你的自定义对象中的UnmarshalBinary方法,从而你就可以获取到你要的数据了。 方法定义 : UnmarshalBinary(data []byte) error
实现示例: 下面演示的是在自定义的结构体 myStru中实现 BinaryMarshaler, BinaryUnmarshaler接口,其中BinaryMarshaler这个可选,因为在你保存数据时go-redis自动帮你完成了,BinaryMarshaler 这个接口必须要你自己实现,否则无法Scan获取自定义的机构体数据。
type myStru struct {
Id string `json:"id"`
Name string `json:"name"`
}
func (m *myStru) MarshalBinary() (data []byte, err error) {
return json.Marshal(m)
}
func (m *myStru) UnmarshalBinary(data []byte) error {
return json.Unmarshal(data, m)
}
map类型的数据获取
如果你存储的是map类型的数据,你可以直接在scan的时候传递一个 []byte类型的数据,然后在自己json.Unmarshal 一下就获取你要的map数据了, 如
var userCache map[string]interface{}
var cval []byte
err := global.GetRdb().Get(cacheKey, &cval)
if err != nil {
global.Log.Error(err.Error())
return Error(err.Error())
}
if err := json.Unmarshal(cval, &userCache); err != nil {
return Error(err.Error())
}
go encoding包中的BinaryMarshaler, BinaryUnmarshaler接口定义参考
// BinaryMarshaler is the interface implemented by an object that can
// marshal itself into a binary form.
//
// MarshalBinary encodes the receiver into a binary form and returns the result.
type BinaryMarshaler interface {
MarshalBinary() (data []byte, err error)
}
// BinaryUnmarshaler is the interface implemented by an object that can
// unmarshal a binary representation of itself.
//
// UnmarshalBinary must be able to decode the form generated by MarshalBinary.
// UnmarshalBinary must copy the data if it wishes to retain the data
// after returning.
type BinaryUnmarshaler interface {
UnmarshalBinary(data []byte) error
}
go-redis Scan数据获取源码参考
// Scan parses bytes `b` to `v` with appropriate type.
//
//nolint:gocyclo
func Scan(b []byte, v interface{}) error {
switch v := v.(type) {
case nil:
return fmt.Errorf("redis: Scan(nil)")
case *string:
*v = util.BytesToString(b)
return nil
case *[]byte:
*v = b
return nil
case *int:
var err error
*v, err = util.Atoi(b)
return err
case *int8:
n, err := util.ParseInt(b, 10, 8)
if err != nil {
return err
}
*v = int8(n)
return nil
case *int16:
n, err := util.ParseInt(b, 10, 16)
if err != nil {
return err
}
*v = int16(n)
return nil
case *int32:
n, err := util.ParseInt(b, 10, 32)
if err != nil {
return err
}
*v = int32(n)
return nil
case *int64:
n, err := util.ParseInt(b, 10, 64)
if err != nil {
return err
}
*v = n
return nil
case *uint:
n, err := util.ParseUint(b, 10, 64)
if err != nil {
return err
}
*v = uint(n)
return nil
case *uint8:
n, err := util.ParseUint(b, 10, 8)
if err != nil {
return err
}
*v = uint8(n)
return nil
case *uint16:
n, err := util.ParseUint(b, 10, 16)
if err != nil {
return err
}
*v = uint16(n)
return nil
case *uint32:
n, err := util.ParseUint(b, 10, 32)
if err != nil {
return err
}
*v = uint32(n)
return nil
case *uint64:
n, err := util.ParseUint(b, 10, 64)
if err != nil {
return err
}
*v = n
return nil
case *float32:
n, err := util.ParseFloat(b, 32)
if err != nil {
return err
}
*v = float32(n)
return err
case *float64:
var err error
*v, err = util.ParseFloat(b, 64)
return err
case *bool:
*v = len(b) == 1 && b[0] == '1'
return nil
case *time.Time:
var err error
*v, err = time.Parse(time.RFC3339Nano, util.BytesToString(b))
return err
case *time.Duration:
n, err := util.ParseInt(b, 10, 64)
if err != nil {
return err
}
*v = time.Duration(n)
return nil
case encoding.BinaryUnmarshaler:
return v.UnmarshalBinary(b)
case *net.IP:
*v = b
return nil
default:
return fmt.Errorf(
"redis: can't unmarshal %T (consider implementing BinaryUnmarshaler)", v)
}
}
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)