把Mysql結果集緩存到Redis的字符串或哈希結構中之後,咱們面臨一個新的問題,即如何爲這些字符串或哈希命名,也就是如何肯定它們的鍵。由於這些數據結構所對應的行都屬於某個結果集,假如能夠找到一種惟一標識結果集的方法,那麼只需爲這些數據結構分配一個惟一的序號,而後把結果集標識符與該序號結合起來,就能惟一標識一個數據結構了。因而,爲字符串和哈希命名的問題就轉化爲肯定結果集標識符的問題。mysql
通過調研,發現一種較爲通用的肯定結果集標識符的方法。正如咱們所知道的,緩存在Redis中的結果集數據都是利用select等sql語句從Mysql中獲取的。一樣的查詢語句會生成一樣的結果集(這裏暫時不討論結果集中每條記錄的順序問題),這一性質恰好能夠用來肯定結果集的惟一標識符。固然,簡單地把整個sql語句做爲結果集標識符是不可取的,一個顯而易見的理由是,未經處理的sql查詢語句均包含若干空格,而Redis的鍵是不容許存在空格的。這時,咱們須要一個能夠把sql語句轉換爲惟一標識符的函數。一般,這一功能由散列函數完成,包括MD5,SHA系列等加密散列函數在內的不少算法都可達到這一目的。redis
肯定結果集標識符以後,從Redis讀數據或向Redis寫數據的思路就很清晰了。對於一個sql語句格式的數據請求,首先計算該語句的MD5並據此獲得結果集標識符,而後利用該標識符在Redis中查找該結果集。注意,結果集中的每一行都有一個相應的鍵,這些鍵都存儲在一個Redis集合結構中。這個集合剛好對應了所需的結果集,因此,該集合的鍵必須包含結果集標識符。若是Redis中不存在這樣一個集合,說明要找的結果集不在Redis中,因此須要執行相應的sql語句,在Mysql中查詢到相應的結果集,而後按照上面所說的辦法把結果集中的每一行以字符串或哈希的形式存入Redis。在Redis中查找相應結果集的代碼以下:算法
[cpp] view plain copysql
// 該函數根據sql語句在Redis中查詢相應的結果集,並返回結果集中每一行所對應的數據結構的鍵 緩存
vector<string> GetCache(sql::Connection *mysql_connection, 數據結構
redisContext *redis_connection, 函數
const string &sql, int ttl, int type) { 加密
vector<string> redis_row_key_vector; spa
string resultset_id = md5(sql); // 計算sql語句的md5,這是惟一標識結果集的關鍵 .net
// type==1時,該函數將查詢相應的STRING集合或將結果集寫入若干STRING
string cache_type = (type == 1) ? "string" : "hash";
// 根據type信息和結果集標識符合成SET鍵
string redis_row_set_key = "resultset." + cache_type + ":" + resultset_id;
redisReply *reply;
// 嘗試從reply中獲取SET中保存的全部鍵
reply = static_cast<redisReply*>(redisCommand(redis_connection,
"SMEMBERS %s",
redis_row_set_key.c_str()));
if (reply->type == REDIS_REPLY_ARRAY) {
// 若是要找的SET不存在,說明Redis中沒有相應的結果集,須要調用Cache2String或
// Cache2Hash函數把數據從Mysql拉取到Redis中
if (reply->elements == 0) {
freeReplyObject(reply);
sql::Statement *stmt = mysql_connection->createStatement();
sql::ResultSet *resultset = stmt->executeQuery(sql);
if (type == 1) {
redis_row_set_key = Cache2String(mysql_connection, redis_connection,
resultset, resultset_id, ttl);
} else {
redis_row_set_key = Cache2Hash(mysql_connection, redis_connection,
resultset, resultset_id, ttl);
}
// 再次嘗試從reply中獲取SET中保存的全部鍵
reply = static_cast<redisReply*>(redisCommand(redis_connection,
"SMEMBERS %s",
redis_row_set_key.c_str()));
delete resultset;
delete stmt;
}
// 把SET中的每一個STRING或HASH鍵存入redis_row_key_vector中
string redis_row_key;
for (int i = 0; i < reply->elements; ++i) {
redis_row_key = reply->element[i]->str;
redis_row_key_vector.push_back(redis_row_key);
}
freeReplyObject(reply);
} else {
freeReplyObject(reply);
throw runtime_error("FAILURE - SMEMBERS error");
}
return redis_row_key_vector;
}
如今咱們已經掌握了肯定Redis中的結果集標識符以及各數據結構的鍵的方法。下一篇文章將研究結果集在Redis中的排序和分頁問題。