英文:
How to HSET time in Golang to redigo (Redis)?
问题
我正在使用redigo在Redis中存储和检索数据。我有一个包含类型定义的结构体,后面跟着时间。我想使用Redis的HSET
命令存储结构体Data
。为了能够使用ScanStruct
函数,我为我的Timestamp
类型添加了一个RedisScan
函数。
问题是Redis将Timestamp
存储为遵循时间字段ext, wall, loc
。你无法从这些字段创建一个新的Time对象,所以这样相当无用。如何正确地将结构体序列化为redigo?
type Timestamp time.Time
func (t *Timestamp) RedisScan(x interface{}) error {
...
}
type Data struct {
Timestamp Timestamp `redis:"timestamp"`
}
func (r *RedisRepo) Write(data Data, key string) error {
conn := r.pool.Get()
defer conn.Close()
conn.Send("HSET", redis.Args{key}.AddFlat(data)...)
}
func (r *RedisRepo) Read(key string) (*Data, error) {
var data Data
conn := r.pool.Get()
defer conn.Close()
v, err := redis.Values(conn.Do("HGETALL", key))
return redis.ScanStruct(v, &data)
}
英文:
I'm using redigo to store and retrieve data in redigo.
I have a struct that contains a type definition following time. I want to store the struct Data
using HSET
in Redis. I have a type definition to be able to use ScanStruct
by adding a function RedisScan
to my Timestamp
type.
The problem is that Redis stores the Timestamp
as ext, wall, loc
following the time fields. You can't create a new Time object from these fields so that's fairly useless. What is the proper way to serialize a struct for redigo?
type Timestamp time.Time
func (t *Timestamp) RedisScan(x interface{}) error {
...
}
type Data struct {
Timestamp Timestamp `redis:"timestamp"`
}
func (r *RedisRepo) Write(data Data, key String) error {
conn := r.pool.Get()
defer conn.Close()
conn.Send("HSET", redis.Args{key}.AddFlat(data)...)
}
func (r *RedisRepo) Read(key string) (*Data, error) {
var data Data
conn := r.pool.Get()
defer conn.Close()
v, err := redis.Values(conn.Do("HGETALL", key))
return redis.ScanStruct(v, &data)
}
答案1
得分: 2
redis.ScanStruct
函数和Args.AddFlat
方法缺少一些功能,这使得它们无法作为通用的编组/解组函数使用。
修复这个问题的方法取决于你的目标是什么。如果你的目标是加载和保存结构体,而不是访问Redis哈希,请参考Save generic struct to redis。
如果你的目标是使用定义的名称和值访问Redis哈希,请编写代码在这些定义和Go值之间进行转换。下面是一个示例,用于定义具有字段"timestamp"和以十进制编码的Unix秒为值的哈希:
type Data struct {
Timestamp time.Time
}
func (r *RedisRepo) Write(data Data, key string) error {
conn := r.pool.Get()
defer conn.Close()
_, err := conn.Do("HSET", key, "timestamp", data.Timestamp.Unix())
return err
}
func (r *RedisRepo) Read(key string) (*Data, error) {
conn := r.pool.Get()
defer conn.Close()
v, err := redis.Values(conn.Do("HGETALL", key))
if err != nil {
return nil, err
}
var fields struct {
Timestamp int64 `redis:"timestamp"`
}
err = redis.ScanStruct(v, &fields)
if err != nil {
return nil, err
}
return &Data{Timestamp: time.Unix(fields.Timestamp, 0)}, nil
}
根据需要调整代码以匹配Redis哈希字段的定义。下面是使用RFC 3339格式表示时间的代码:
type Data struct {
Timestamp time.Time
}
func (r *RedisRepo) Write(data Data, key string) error {
conn := r.pool.Get()
defer conn.Close()
_, err := conn.Do("HSET", key, "timestamp", data.Timestamp.Format(time.RFC3339))
return err
}
func (r *RedisRepo) Read(key string) (*Data, error) {
conn := r.pool.Get()
defer conn.Close()
v, err := redis.Values(conn.Do("HGETALL", key))
if err != nil {
return nil, err
}
var fields struct {
Timestamp string `redis:"timestamp"`
}
err = redis.ScanStruct(v, &fields)
if err != nil {
return nil, err
}
t, err := time.Parse(time.RFC3339, fields.Timestamp)
if err != nil {
return nil, err
}
return &Data{Timestamp: t}, nil
}
上述的Read
示例是为了方便扩展到多个字段而编写的。如果应用程序只需要访问一个字段,可以将fields
变量和ScanStruct
替换为调用redis.Int64(conn.Do("HGET", key, "timestamp")
或redis.String(conn.Do("HGET", key, "timestamp")
。
英文:
The redis.ScanStruct
function and the Args.AddFlat
method are missing features that make the pair usable as general purpose marshal/unmarshal functions.
The approach for fixing the problem depends on what your goal is.
See Save generic struct to redis if your goal is to load and save structs, not to access a Redis hash.
If your goal is to access Redis hashes with defined names and values, then write code that translates between those definitions and Go values. Here's an example for a hash that's defined to have field "timestamp" with a value as decimal encoded Unix seconds:
type Data struct {
Timestamp time.Time
}
func (r *RedisRepo) Write(data Data, key string) error {
conn := r.pool.Get()
defer conn.Close()
_, err := conn.Do("HSET", key, "timestamp", data.Timestamp.Unix())
return err
}
func (r *RedisRepo) Read(key string) (*Data, error) {
conn := r.pool.Get()
defer conn.Close()
v, err := redis.Values(conn.Do("HGETALL", key))
if err != nil {
return nil, err
}
var fields struct {
Timestamp int64 `redis:"timestamp"`
}
err = redis.ScanStruct(v, &fields)
if err != nil {
return nil, err
}
return &Data{Timestamp: time.Unix(fields.Timestamp, 0)}, nil
}
Adjust the code as needed to match the Redis hash field definitions. Here's the code for time in RFC 3339 format:
type Data struct {
Timestamp time.Time
}
func (r *RedisRepo) Write(data Data, key string) error {
conn := r.pool.Get()
defer conn.Close()
_, err := conn.Do("HSET", key, "timestamp", data.Timestamp.Format(time.RFC3339))
return err
}
func (r *RedisRepo) Read(key string) (*Data, error) {
conn := r.pool.Get()
defer conn.Close()
v, err := redis.Values(conn.Do("HGETALL", key))
if err != nil {
return nil, err
}
var fields struct {
Timestamp string `redis:"timestamp"`
}
err = redis.ScanStruct(v, &fields)
if err != nil {
return nil, err
}
t, err := time.Parse(time.RFC3339, fields.Timestamp)
if err != nil {
return nil, err
}
return &Data{Timestamp: t}, nil
}
The Read
examples above are written so that the examples are easy to extend to multiple fields. If the application only needs to access a single field, replace the fields
variable and ScanStruct
nonsense with a call to redis.Int64(conn.Do("HGET", key, "timestamp")
or redis.String(conn.Do("HGET", key, "timestamp")
答案2
得分: 0
如果要向Redis的哈希集合中添加内容,至少需要以下三个值:
- 哈希集合的名称
- 哈希集合的键(也可以稍后添加额外的键)
- 哈希集合的值
编写代码的最佳方式是在redigo库上添加一个包装器,以抽象实现并将依赖注入到你的代码中。
// 不是最佳方式
func dummy() {
redisConn := redisCache.pool.Get()
defer redisConn.Close()
response, err := redisConn.Do("HSET", args...)
}
type Implementation struct {
RedisImplementation RedigoAbstractionConnection
}
// 最佳方式
func (i Implementation) AddDataToRedisHashSet(hashName string, key string, value string) error {
var args = []interface{}{hashName}
args = append(args, key, value)
_, err := i.RedisImplementation.HSET(args...) // 返回一个接口和一个错误
if err != nil {
// 处理错误
}
return nil
}
以上是要翻译的内容。
英文:
If you are going to add something into Hash Set of Redis you need to have these three values at least.
- A name to your hashset
- Keys for your hashset(can add extra keys later on as well)
- Values for your hashset
Best way of coding this is to add a wrapper on the redigo library to abstract the implementation and inject the dependency into your code.
// Not the best way
func dummy(){
redisConn := redisCache.pool.Get()
defer redisConn.Close()
response, err := redisConn.Do("HSET", args...)
}
type Implementation struct {
RedisImplementation RedigoAbstractionConnection
}
// Best way
func (i Implementation) AddDataToRedisHashSet(hashName string, key string, value string) error {
var args = []interface{}{hashName}
args = append(args, key, value)
_, err := i.RedisImplementation.HSET(args...) // Returns an interface and an error
if err != nil{
// Handle Error
}
return nil
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论