Redis缓存返回部分数据问题:Go语言Postgres+Redis缓存实现异常
问题:Postgres+Redis缓存场景下GetAllUsers接口后续请求字段缺失
我实现了Postgres结合Redis缓存的GetAllUsers接口,首次请求能返回完整用户数据,但后续请求会出现部分字段缺失的情况。相关代码与User结构体定义如下:
接口实现代码
func (usr *UserImplementation) GetAllUsers(ctx context.Context) ([]models.User, error) { cachedUsers, err := databaseapi.Redis_CacheDB_Api() if err != nil { return nil, fmt.Errorf("error connecting to Redis cache: %v", err) } // pipe := cachedUsers.TxPipeline() cachedData, err := cachedUsers.Get(ctx, "users").Result() if err != nil && err != redis.Nil { return nil, fmt.Errorf("error retrieving cached data: %v", err) } if cachedData != "" { // Data found in the cache, return the cached data var cachedUsers []models.User err := json.Unmarshal([]byte(cachedData), &cachedUsers) if err != nil { return nil, fmt.Errorf("error unmarshaling cached data: %v", err) } return cachedUsers, nil } users, err := usr.pg.Postgres_DB_Api().DB.GetAllUsers(ctx) if err != nil { return nil, fmt.Errorf("error: %v", err.Error()) } cacheData, err := json.Marshal(users) if err != nil { return nil, fmt.Errorf("error marshaling data for caching: %v", err) } expiration := time.Hour err = cachedUsers.Set(ctx, "users", string(cacheData), expiration).Err() if err != nil { return nil, fmt.Errorf("error caching data: %v", err) } return models.DatabaseUsersToUsers(users), nil }
User结构体定义
type User struct { ID uuid.UUID `json:"id"` FirstName string `json:"first_name"` LastName string `json:"last_name"` OtherName string `json:"other_name"` Username string `json:"user_name"` Password string `json:"password"` Email string `json:"email"` ProfileImage string `json:"profile_image"` Status string `json:"status"` IsAdmin bool `json:"is_admin"` Role string `json:"role"` Gender string `json:"gender"` PhoneNumber string `json:"phone_number"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` }
问题根因
核心问题是缓存的数据与接口返回的数据类型不匹配:
- 从Postgres查询到的
users是数据库层结构体(推测为models.DatabaseUser),你直接将其序列化存入Redis - 从Redis取出反序列化时,却用了接口返回的
models.User类型 - 最终返回时又通过
models.DatabaseUsersToUsers(users)做类型转换,这导致缓存的原始数据库结构体和API结构体的字段、JSON标签可能存在差异,反序列化时出现字段缺失
解决方案
将转换后的API结构体存入缓存,而非原始数据库结构体,修改后的代码如下:
func (usr *UserImplementation) GetAllUsers(ctx context.Context) ([]models.User, error) { cachedUsers, err := databaseapi.Redis_CacheDB_Api() if err != nil { return nil, fmt.Errorf("error connecting to Redis cache: %v", err) } cachedData, err := cachedUsers.Get(ctx, "users").Result() if err != nil && err != redis.Nil { return nil, fmt.Errorf("error retrieving cached data: %v", err) } if cachedData != "" { var cachedUsers []models.User err := json.Unmarshal([]byte(cachedData), &cachedUsers) if err != nil { return nil, fmt.Errorf("error unmarshaling cached data: %v", err) } return cachedUsers, nil } // 查询数据库原始数据 dbUsers, err := usr.pg.Postgres_DB_Api().DB.GetAllUsers(ctx) if err != nil { return nil, fmt.Errorf("error: %v", err.Error()) } // 先转换为API用的User类型 apiUsers := models.DatabaseUsersToUsers(dbUsers) // 序列化转换后的API数据存入缓存 cacheData, err := json.Marshal(apiUsers) if err != nil { return nil, fmt.Errorf("error marshaling data for caching: %v", err) } expiration := time.Hour err = cachedUsers.Set(ctx, "users", string(cacheData), expiration).Err() if err != nil { return nil, fmt.Errorf("error caching data: %v", err) } return apiUsers, nil }
额外检查点
- 确认
models.DatabaseUser和models.User的JSON标签完全对应,避免标签不一致导致反序列化字段缺失 - 检查
DatabaseUsersToUsers转换函数是否正确处理了所有字段,无遗漏 - 确保需要缓存的字段都是导出状态(结构体字段首字母大写),未导出字段会被JSON序列化自动忽略
内容的提问来源于stack exchange,提问作者Daniel Dexoangle
相关产品推荐
相关产品推荐

