redis在游戏服务器中的使用初探(三) 信息存储

摘要:

搭建了服务器环境 有了客户端 我们来假想下以下应用场景:
我们简单举个实例来描述下Hash的应用场景,比如我们要存储一个用户信息对象数据,包含以下信息:
用户ID,为查找的key,
存储的value用户对象包含姓名userName,密码校验值passwordMD5,手机号码telephoneNum , 微信名称wechatName 等信息.
将如何在redis中存储和操作?

 

 

搭建了服务器环境 有了客户端 我们来假想下以下应用场景:

我们简单举个实例来描述下Hash的应用场景,比如我们要存储一个用户信息对象数据,包含以下信息:
           用户ID,为查找的key,
           存储的value用户对象包含姓名userName,密码校验值passwordMD5,手机号码telephoneNum , 微信名称wechatName 等信息.

      如果用普通的key/value结构来存储, 可以使用这种方式来存储:
(1)   第一种方式将用户ID作为查找key,把其他信息封装成一个对象以序列化的方式存储,需要一次次地发送和返回。
           如:set "u76493029" "大咖11523,5623654521236,15823564493,幽游仙水"
           这种方式的缺点是,增加了序列化/反序列化的开销,并且在需要修改其中一项信息时,需要把整个对象取回,并且修改操作需要对并发进行保护,引入CAS等复杂问题。   

复制代码
  1 // myRedisCli.cpp: 定义控制台应用程序的入口点。
  2 //
  3 
  4 #include "stdafx.h"
  5 #include <assert.h>
  6 #include <winsock2.h>
  7 #include <string.h>
  8 #include <tuple>
  9 #include <iostream>
 10 #include <sstream>
 11 #include <string>
 12 #include <string.h>
 13 #include"hiredis/hiredis.h"
 14 
 15 using namespace std;
 16 
 17 class RedisConnect {
 18 public:
 19     RedisConnect() :redisCon(nullptr), reply(nullptr) {}
 20 
 21     bool Init(const std::string& ip, int port) {
 22         if (nullptr != redisCon) {
 23             return false;
 24         }
 25         redisCon = redisConnect(ip.c_str(), port);
 26         if (redisCon->err) {
 27             std::cerr << "error code : " << redisCon->err << ". " << redisCon->errstr << std::endl;
 28             return false;
 29         }
 30 
 31         return true;
 32     }
 33     void freeReply()
 34     {
 35         if (nullptr != reply)
 36         {
 37             ::freeReplyObject(reply);
 38             reply = nullptr;
 39         }
 40     }
 41 
 42     template<class T>
 43     bool GetVal(const std::string& key, T& value) {
 44         return Get(key, value);
 45     }
 46 
 47     template<class T, class... Args>
 48     bool HashSet(const std::string command, T head, Args... rest) {
 49         std::stringstream ss;
 50         ss << command << " " << head << " ";
 51         return HashSetInner(ss, rest...);
 52     }
 53 
 54     template<typename T>
 55     bool Set(const std::string & key, const T& value)
 56     {
 57         bool bret = false;
 58         std::stringstream ss;
 59         ss << "SET " << key << " " << value;
 60         std::string s;
 61         getline(ss, s);
 62         return Set(s);
 63     }
 64 
 65 
 66     bool InitWithTimeout(const std::string& ip, int port, int seconds) {
 67         if (nullptr != redisCon) {
 68             return false;
 69         }
 70         struct timeval tv;
 71         tv.tv_sec = seconds;
 72         tv.tv_usec = 0;
 73         redisCon = redisConnectWithTimeout(ip.c_str(), port, tv);
 74         if (redisCon->err) {
 75             std::cerr << "error code : " << redisCon->err << ". " << redisCon->errstr << std::endl;
 76             return false;
 77         }
 78         return true;
 79     }
 80 
 81     ~RedisConnect() {
 82         freeReply();
 83         if (nullptr == redisCon) {
 84             redisFree(redisCon);
 85             redisCon = nullptr;
 86         }
 87     }
 88 private:
 89     void GetString(const std::string & key)
 90     {
 91         freeReply();
 92         reply = (redisReply*)::redisCommand(redisCon, "GET %s", key.c_str());
 93     }
 94 
 95     bool Get(const std::string& key, std::string & value) {
 96         bool bret = false;
 97         GetString(key);
 98         if (nullptr == reply) {
 99             std::cout << "Failed to execute " << __FUNCTION__ << std::endl << std::endl;
100             return bret;
101         }
102         else if (reply->type == REDIS_REPLY_NIL) {
103             std::cout << __FUNCTION__ << ". Key = \"" << key << "\" find nothing" << std::endl << std::endl;
104             return bret;
105         }else if( reply->type != REDIS_REPLY_STRING) {
106             std::cout << "Failed to execute " << __FUNCTION__ << std::endl << std::endl;
107             return bret;
108         }
109         value = reply->str;
110         bret = true;
111         return bret;
112     }
113 
114     bool Get(const std::string& key, int & value) {
115         bool bret = false;
116         GetString(key);
117         if (nullptr == reply) {
118             std::cout << "Failed to execute " << __FUNCTION__ << std::endl << std::endl;
119             return bret;
120         }
121         else if (reply->type == REDIS_REPLY_NIL) {
122             std::cout << __FUNCTION__ << ". Key = \"" << key << "\" find nothing" << std::endl << std::endl;
123             return bret;
124         }
125         else if (reply->type != REDIS_REPLY_STRING) {
126             std::cout << "Failed to execute " << __FUNCTION__ << std::endl << std::endl;
127             return bret;
128         }
129         value = ::atoi(reply->str);
130         bret = true;
131         return bret;
132     }
133 
134     bool Get(const std::string& key, float & value) {
135         bool bret = false;
136         GetString(key);
137         if (nullptr == reply) {
138             std::cout << "Failed to execute " << __FUNCTION__ << std::endl << std::endl;
139             return bret;
140         }
141         else if (reply->type == REDIS_REPLY_NIL) {
142             std::cout << __FUNCTION__ << ". Key = \"" << key << "\" find nothing" << std::endl << std::endl;
143             return bret;
144         }
145         else if (reply->type != REDIS_REPLY_STRING) {
146             std::cout << "Failed to execute " << __FUNCTION__ << std::endl << std::endl;
147             return bret;
148         }
149         value = ::atof(reply->str);
150         bret = true;
151         return bret;
152     }
153 
154     bool HashSetInner(std::stringstream& ss)
155     {
156         std::string data;
157         getline(ss, data);
158         //std::cout << __FUNCTION__ << " " << data << std::endl;
159         bool bret = false;
160         freeReply();
161         reply = (redisReply*)::redisCommand(redisCon, data.c_str());
162 
163         if (reply->type == REDIS_REPLY_ERROR ||
164             (reply->type == REDIS_REPLY_STATUS && _stricmp(reply->str, "OK") != 0))
165         {
166             if (reply->str != nullptr) {
167                 std::cout << reply->str << std::endl;
168             }
169             std::cout << "Failed to execute " << __FUNCTION__ << std::endl << std::endl;
170             return bret;
171         }
172 
173         bret = true;
174 
175         return bret;
176     }
177 
178     template<class T, class... Args>
179     bool HashSetInner(std::stringstream& ss, T head, Args... rest)
180     {
181         ss << head << " ";
182         return HashSetInner(ss, rest...);
183     }
184 
185     bool Set(std::string data)
186     {
187         bool bret = false;
188         freeReply();
189         reply = (redisReply*)::redisCommand(redisCon, data.c_str());
190 
191         if (!(reply->type == REDIS_REPLY_STATUS && _stricmp(reply->str, "OK") == 0))
192         {
193             std::cout << reply->str << std::endl;
194             std::cout << "Failed to execute " << __FUNCTION__ << std::endl;
195             return bret;
196         }
197         bret = true;
198         return bret;
199     }
200 
201     redisContext* redisCon;
202     redisReply * reply;
203 };
204 
205 typedef struct userscore {
206     string    userID;
207     int        score;
208 }UserScore;
209 
210 typedef struct userwinpercent {
211     string    userID;
212     float    winpercent;
213 }UserWinPercent;
214 
215 
216 
217 int main()
218 {
219     RedisConnect r;
220 
221     bool b = r.InitWithTimeout("127.0.0.1", 6379, 5);
222     if (!b)
223         return -1;
224 
225     UserScore us{ "user:u76493029:socre",9999 };
226     UserWinPercent uwp{ "user:u76493029:winPercent",67.3 };
227 
228     if (false == r.Set(us.userID, us.score) || false == r.Set(uwp.userID, uwp.winpercent)) {
229         std::cerr << "operate redis error!" << std::endl;
230         return -1;
231     }
232     int score = 0;
233     float winpercent = 0.0;
234     if (false == r.GetVal(us.userID, score) || false == r.GetVal(uwp.userID, winpercent)) {
235         std::cerr << "operate redis error!" << std::endl;
236         return -1;
237     }
238     else {
239         std::cout << "key = " << us.userID << ". find value = " << score << std::endl;
240         std::cout << "key = " << uwp.userID << ". find value = " << winpercent << std::endl;
241     }
242     
243 
244     std::cout << "finish !" << std::endl;
245     return 0;
246 }
View Code
复制代码


运行结果如图:

 redis原生命令在客户端验证如下:

(此版本redis中文支持不太好)

 

 


(2)   第二种方法是这个用户信息对象有多少成员就存成多少个key-value对儿,用用户ID+对应属性的名称作为唯一标识来取得对应属性的值,不需要一次次地设置,可以一次设置多个,但命令信息有些冗余。
  比如userid对应玩家的分数 棋牌玩家的游戏场数 玩家的胜率等

  如:mset user:u76493029:socre 9999       user:u76493029:gameCount  723    user:u76493029:winPercent 67.3
  虽然省去了序列化开销和并发问题,但是用户ID为重复存储,如果存在大量这样的数据,内存浪费还是非常可观的。
  使用上一篇的hredis库进行代码操作 代码如下:

复制代码
  1 // myRedisCli.cpp: 定义控制台应用程序的入口点。
  2 //
  3 
  4 #include "stdafx.h"
  5 #include <assert.h>
  6 #include <winsock2.h>
  7 #include <string.h>
  8 #include <tuple>
  9 #include <iostream>
 10 #include <sstream>
 11 #include <string>
 12 #include <string.h>
 13 #include"hiredis/hiredis.h"
 14 
 15 using namespace std;
 16 
 17 class RedisConnect {
 18 public:
 19     RedisConnect() :redisCon(nullptr), reply(nullptr) {}
 20 
 21     bool Init(const std::string& ip, int port) {
 22         if (nullptr != redisCon) {
 23             return false;
 24         }
 25         redisCon = redisConnect(ip.c_str(), port);
 26         if (redisCon->err) {
 27             std::cerr << "error code : " << redisCon->err << ". " << redisCon->errstr << std::endl;
 28             return false;
 29         }
 30 
 31         return true;
 32     }
 33     void freeReply()
 34     {
 35         if (nullptr != reply)
 36         {
 37             ::freeReplyObject(reply);
 38             reply = nullptr;
 39         }
 40     }
 41 
 42     template<class T>
 43     bool GetVal(const std::string& key, T& value) {
 44         return Get(key, value);
 45     }
 46 
 47     template<class T, class... Args>
 48     bool HashSet(const std::string command, T head, Args... rest) {
 49         std::stringstream ss;
 50         ss << command << " " << head << " ";
 51         return HashSetInner(ss, rest...);
 52     }
 53 
 54     template<typename T>
 55     bool Set(const std::string & key, const T& value)
 56     {
 57         bool bret = false;
 58         std::stringstream ss;
 59         ss << "SET " << key << " " << value;
 60         std::string s;
 61         getline(ss, s);
 62         return Set(s);
 63     }
 64 
 65 
 66     bool InitWithTimeout(const std::string& ip, int port, int seconds) {
 67         if (nullptr != redisCon) {
 68             return false;
 69         }
 70         struct timeval tv;
 71         tv.tv_sec = seconds;
 72         tv.tv_usec = 0;
 73         redisCon = redisConnectWithTimeout(ip.c_str(), port, tv);
 74         if (redisCon->err) {
 75             std::cerr << "error code : " << redisCon->err << ". " << redisCon->errstr << std::endl;
 76             return false;
 77         }
 78         return true;
 79     }
 80 
 81     ~RedisConnect() {
 82         freeReply();
 83         if (nullptr == redisCon) {
 84             redisFree(redisCon);
 85             redisCon = nullptr;
 86         }
 87     }
 88 private:
 89     void GetString(const std::string & key)
 90     {
 91         freeReply();
 92         reply = (redisReply*)::redisCommand(redisCon, "GET %s", key.c_str());
 93     }
 94 
 95     bool Get(const std::string& key, std::string & value) {
 96         bool bret = false;
 97         GetString(key);
 98         if (nullptr == reply) {
 99             std::cout << "Failed to execute " << __FUNCTION__ << std::endl << std::endl;
100             return bret;
101         }
102         else if (reply->type == REDIS_REPLY_NIL) {
103             std::cout << __FUNCTION__ << ". Key = \"" << key << "\" find nothing" << std::endl << std::endl;
104             return bret;
105         }else if( reply->type != REDIS_REPLY_STRING) {
106             std::cout << "Failed to execute " << __FUNCTION__ << std::endl << std::endl;
107             return bret;
108         }
109         value = reply->str;
110         bret = true;
111         return bret;
112     }
113 
114     bool Get(const std::string& key, int & value) {
115         bool bret = false;
116         GetString(key);
117         if (nullptr == reply) {
118             std::cout << "Failed to execute " << __FUNCTION__ << std::endl << std::endl;
119             return bret;
120         }
121         else if (reply->type == REDIS_REPLY_NIL) {
122             std::cout << __FUNCTION__ << ". Key = \"" << key << "\" find nothing" << std::endl << std::endl;
123             return bret;
124         }
125         else if (reply->type != REDIS_REPLY_STRING) {
126             std::cout << "Failed to execute " << __FUNCTION__ << std::endl << std::endl;
127             return bret;
128         }
129         value = ::atoi(reply->str);
130         bret = true;
131         return bret;
132     }
133 
134     bool Get(const std::string& key, float & value) {
135         bool bret = false;
136         GetString(key);
137         if (nullptr == reply) {
138             std::cout << "Failed to execute " << __FUNCTION__ << std::endl << std::endl;
139             return bret;
140         }
141         else if (reply->type == REDIS_REPLY_NIL) {
142             std::cout << __FUNCTION__ << ". Key = \"" << key << "\" find nothing" << std::endl << std::endl;
143             return bret;
144         }
145         else if (reply->type != REDIS_REPLY_STRING) {
146             std::cout << "Failed to execute " << __FUNCTION__ << std::endl << std::endl;
147             return bret;
148         }
149         value = ::atof(reply->str);
150         bret = true;
151         return bret;
152     }
153 
154     bool HashSetInner(std::stringstream& ss)
155     {
156         std::string data;
157         getline(ss, data);
158         //std::cout << __FUNCTION__ << " " << data << std::endl;
159         bool bret = false;
160         freeReply();
161         reply = (redisReply*)::redisCommand(redisCon, data.c_str());
162 
163         if (reply->type == REDIS_REPLY_ERROR ||
164             (reply->type == REDIS_REPLY_STATUS && _stricmp(reply->str, "OK") != 0))
165         {
166             if (reply->str != nullptr) {
167                 std::cout << reply->str << std::endl;
168             }
169             std::cout << "Failed to execute " << __FUNCTION__ << std::endl << std::endl;
170             return bret;
171         }
172 
173         bret = true;
174 
175         return bret;
176     }
177 
178     template<class T, class... Args>
179     bool HashSetInner(std::stringstream& ss, T head, Args... rest)
180     {
181         ss << head << " ";
182         return HashSetInner(ss, rest...);
183     }
184 
185     bool Set(std::string data)
186     {
187         bool bret = false;
188         freeReply();
189         reply = (redisReply*)::redisCommand(redisCon, data.c_str());
190 
191         if (!(reply->type == REDIS_REPLY_STATUS && _stricmp(reply->str, "OK") == 0))
192         {
193             std::cout << reply->str << std::endl;
194             std::cout << "Failed to execute " << __FUNCTION__ << std::endl;
195             return bret;
196         }
197         bret = true;
198         return bret;
199     }
200 
201     redisContext* redisCon;
202     redisReply * reply;
203 };
204 
205 typedef struct userscore {
206     string    userID;
207     int        score;
208 }UserScore;
209 
210 typedef struct userwinpercent {
211     string    userID;
212     float    winpercent;
213 }UserWinPercent;
214 
215 
216 
217 int main()
218 {
219     RedisConnect r;
220 
221     bool b = r.InitWithTimeout("127.0.0.1", 6379, 5);
222     if (!b)
223         return -1;
224 
225     UserScore us{ "user:u76493029:socre",9999 };
226     UserWinPercent uwp{ "user:u76493029:winPercent",67.3 };
227 
228     if (false == r.Set(us.userID, us.score) || false == r.Set(uwp.userID, uwp.winpercent)) {
229         std::cerr << "operate redis error!" << std::endl;
230         return -1;
231     }
232     int score = 0;
233     float winpercent = 0.0;
234     if (false == r.GetVal(us.userID, score) || false == r.GetVal(uwp.userID, winpercent)) {
235         std::cerr << "operate redis error!" << std::endl;
236         return -1;
237     }
238     else {
239         std::cout << "key = " << us.userID << ". find value = " << score << std::endl;
240         std::cout << "key = " << uwp.userID << ". find value = " << winpercent << std::endl;
241     }
242     
243 
244     std::cout << "finish !" << std::endl;
245     return 0;
246 }
View Code
复制代码

运行结果如图:

 redis原生命令在客户端验证如下:

 


(3)第三个,如果key下的value很多,而且各自的属性值互相是独立的。例如玩家包里的道具,那么使用上面的方法存储搜索起来其实是一种效率很低的方案。
Redis提供的Hash很好的解决了这个问题,Redis的Hash实际是内部存储的Value为一个HashMap,并提供了直接存取这个Map成员的接口

   如:hmset user:u76493029  itemID  78335267  itemType 武器  itemName 刀  itemCount 1  itemValue 4       
   也就是说,Key仍然是用户ID, value是一个Map,这个Map的key是成员的属性名,value是属性值,这样对数据的修改和存取都可以直接通过其内部Map的Key(Redis里称内部Map的key为field), 也就是通过 key(用户ID) + field(属性标签) 就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题。很好的解决了问题。
这里同时需要注意,Redis提供了接口(hgetall)可以直接取到全部的属性数据,但是如果内部Map的成员很多,那么涉及到遍历整个内部Map的操作,由于Redis单线程模型的缘故,这个遍历操作可能会比较耗时,而另其它客户端的请求完全不响应,这点需要格外注意。

复制代码
  1 // myRedisCli.cpp: 定义控制台应用程序的入口点。
  2 //
  3 
  4 #include "stdafx.h"
  5 #include <assert.h>
  6 #include <winsock2.h>
  7 #include <string.h>
  8 #include <tuple>
  9 #include <iostream>
 10 #include <sstream>
 11 #include <string.h>
 12 #include <string>
 13 #include <assert.h>
 14 #include"hiredis/hiredis.h"
 15 
 16 using namespace std;
 17 
 18 class RedisConnect {
 19 public:
 20     RedisConnect() :redisCon(nullptr), reply(nullptr) {}
 21 
 22     bool Init(const std::string& ip, int port) {
 23         if (nullptr != redisCon) {
 24             return false;
 25         }
 26         redisCon = redisConnect(ip.c_str(), port);
 27         if (redisCon->err) {
 28             std::cerr << "error code : " << redisCon->err << ". " << redisCon->errstr << std::endl;
 29             return false;
 30         }
 31 
 32         return true;
 33     }
 34     void freeReply()
 35     {
 36         if (nullptr != reply)
 37         {
 38             ::freeReplyObject(reply);
 39             reply = nullptr;
 40         }
 41     }
 42 
 43     template<class T>
 44     bool GetVal(const std::string& key, T& value) {
 45         return Get(key, value);
 46     }
 47 
 48     template<class T, class... Args>
 49     bool HashSet(const std::string command, T head, Args... rest) {
 50         std::stringstream ss;
 51         ss << command << " " << head << " ";
 52         return HashSetInner(ss, rest...);
 53     }
 54 
 55     bool HGetAll(const string& key) {
 56         bool bret = false;
 57         freeReply();
 58         string commandStr = "hgetall ";
 59         commandStr += key;
 60         reply = (redisReply*)::redisCommand(redisCon, commandStr.c_str());
 61         if (nullptr == reply || 0 == reply->elements ) {
 62             std::cout << "Failed to execute " << __FUNCTION__ << std::endl << std::endl;
 63             return bret;
 64         }
 65         std::cout << "HGETALL key = " << key << std::endl;
 66         for (int i = 0; i < reply->elements; i++) {
 67             redisReply* p = reply->element[i];
 68             std::cout << "element[" << i + 1 << "] = " << p->str << std::endl;
 69         }
 70 
 71             
 72         bret = true;
 73         return bret;
 74     }
 75 
 76     template<typename T>
 77     bool Set(const std::string & key, const T& value)
 78     {
 79         bool bret = false;
 80         std::stringstream ss;
 81         ss << "SET " << key << " " << value;
 82         std::string s;
 83         getline(ss, s);
 84         return Set(s);
 85     }
 86 
 87 
 88     bool InitWithTimeout(const std::string& ip, int port, int seconds) {
 89         if (nullptr != redisCon) {
 90             return false;
 91         }
 92         struct timeval tv;
 93         tv.tv_sec = seconds;
 94         tv.tv_usec = 0;
 95         redisCon = redisConnectWithTimeout(ip.c_str(), port, tv);
 96         if (redisCon->err) {
 97             std::cerr << "error code : " << redisCon->err << ". " << redisCon->errstr << std::endl;
 98             return false;
 99         }
100         return true;
101     }
102 
103     ~RedisConnect() {
104         freeReply();
105         if (nullptr == redisCon) {
106             redisFree(redisCon);
107             redisCon = nullptr;
108         }
109     }
110 private:
111     void GetString(const std::string & key)
112     {
113         freeReply();
114         reply = (redisReply*)::redisCommand(redisCon, "GET %s", key.c_str());
115     }
116 
117     bool Get(const std::string& key, std::string & value) {
118         bool bret = false;
119         GetString(key);
120         if (nullptr == reply) {
121             std::cout << "Failed to execute " << __FUNCTION__ << std::endl << std::endl;
122             return bret;
123         }
124         else if (reply->type == REDIS_REPLY_NIL) {
125             std::cout << __FUNCTION__ << ". Key = \"" << key << "\" find nothing" << std::endl << std::endl;
126             return bret;
127         }else if( reply->type != REDIS_REPLY_STRING) {
128             std::cout << "Failed to execute " << __FUNCTION__ << std::endl << std::endl;
129             return bret;
130         }
131         value = reply->str;
132         bret = true;
133         return bret;
134     }
135 
136     bool Get(const std::string& key, int & value) {
137         bool bret = false;
138         GetString(key);
139         if (nullptr == reply) {
140             std::cout << "Failed to execute " << __FUNCTION__ << std::endl << std::endl;
141             return bret;
142         }
143         else if (reply->type == REDIS_REPLY_NIL) {
144             std::cout << __FUNCTION__ << ". Key = \"" << key << "\" find nothing" << std::endl << std::endl;
145             return bret;
146         }
147         else if (reply->type != REDIS_REPLY_STRING) {
148             std::cout << "Failed to execute " << __FUNCTION__ << std::endl << std::endl;
149             return bret;
150         }
151         value = ::atoi(reply->str);
152         bret = true;
153         return bret;
154     }
155 
156     bool Get(const std::string& key, float & value) {
157         bool bret = false;
158         GetString(key);
159         if (nullptr == reply) {
160             std::cout << "Failed to execute " << __FUNCTION__ << std::endl << std::endl;
161             return bret;
162         }
163         else if (reply->type == REDIS_REPLY_NIL) {
164             std::cout << __FUNCTION__ << ". Key = \"" << key << "\" find nothing" << std::endl << std::endl;
165             return bret;
166         }
167         else if (reply->type != REDIS_REPLY_STRING) {
168             std::cout << "Failed to execute " << __FUNCTION__ << std::endl << std::endl;
169             return bret;
170         }
171         value = ::atof(reply->str);
172         bret = true;
173         return bret;
174     }
175 
176     bool HashSetInner(std::stringstream& ss)
177     {
178         std::string data;
179         getline(ss, data);
180         //std::cout << __FUNCTION__ << " " << data << std::endl;
181         bool bret = false;
182         freeReply();
183         reply = (redisReply*)::redisCommand(redisCon, data.c_str());
184 
185         if (reply->type == REDIS_REPLY_ERROR ||
186             (reply->type == REDIS_REPLY_STATUS && _stricmp(reply->str, "OK") != 0))
187         {
188             if (reply->str != nullptr) {
189                 std::cout << reply->str << std::endl;
190             }
191             std::cout << "Failed to execute " << __FUNCTION__ << std::endl << std::endl;
192             return bret;
193         }
194 
195         bret = true;
196 
197         return bret;
198     }
199 
200     template<class T, class... Args>
201     bool HashSetInner(std::stringstream& ss, T head, Args... rest)
202     {
203         ss << head << " ";
204         return HashSetInner(ss, rest...);
205     }
206 
207     bool Set(std::string data)
208     {
209         bool bret = false;
210         freeReply();
211         reply = (redisReply*)::redisCommand(redisCon, data.c_str());
212 
213         if (!(reply->type == REDIS_REPLY_STATUS && _stricmp(reply->str, "OK") == 0))
214         {
215             std::cout << reply->str << std::endl;
216             std::cout << "Failed to execute " << __FUNCTION__ << std::endl;
217             return bret;
218         }
219         bret = true;
220         return bret;
221     }
222 
223     redisContext* redisCon;
224     redisReply * reply;
225 };
226 //=======================================================================
227 //用户数据结构
228 typedef struct iteminfo {
229     string    itemID;
230     string    itemType;
231     string  itemName;
232     int        itemCount;
233     string    itemValue;    //DEF:23 防御力23  ATT:4 攻击力4 MED:6 医疗6
234 }ItemInfo;
235 //=================================================================
236 
237 
238 
239 int main()
240 {
241     RedisConnect r;
242 
243     bool b = r.InitWithTimeout("127.0.0.1", 6379, 5);
244     if (!b)
245         return -1;
246 
247     string userID = "user:u76493029";
248     ItemInfo itemInfo{ "78335267","武器","绝影",1,"ATT:4" };
249 
250     if (false == r.HashSet("hmset",userID, "itemID", itemInfo.itemID, "itemType", itemInfo.itemType, "itemName", itemInfo.itemName,
251         "itemCount", itemInfo.itemCount, "itemValue", itemInfo.itemValue)) {
252         std::cerr << "operate redis error ! " << std::endl;
253         return -1;
254     }
255     //todo HGETALL HGET KEY FIELD
256     b = r.HGetAll(userID);
257 
258     std::cout << "finish !" << std::endl;
259     return 0;
260 }
View Code
复制代码

 

运行结果如图:

 

redis原生命令在客户端验证如下:

 

 

参考  

https://blog.csdn.net/chenjiayi_yun/article/details/18887647

http://www.cnblogs.com/stephen-liu74/archive/2012/04/16/2370212.html

posted on   itdef  阅读(1191)  评论(0编辑  收藏  举报

编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
历史上的今天:
2016-08-30 操作系统学习笔记(一) 段权限转移规则

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示