標籤:資料庫 redis 資料結構 緩衝
把Mysql結果集緩衝到Redis的字串或雜湊結構中以後,我們面臨一個新的問題,即如何為這些字串或雜湊命名,也就是如何確定它們的鍵。因為這些資料結構所對應的行都屬於某個結果集,假如可以找到一種唯一標識結果集的方法,那麼只需為這些資料結構分配一個唯一的序號,然後把結果集標識符與該序號結合起來,就能唯一標識一個資料結構了。於是,為字串和雜湊命名的問題就轉化為確定結果集標識符的問題。
經過調研,發現一種較為通用的確定結果集標識符的方法。正如我們所知道的,緩衝在Redis中的結果集資料都是利用select等sql語句從Mysql中擷取的。同樣的查詢語句會產生同樣的結果集(這裡暫時不討論結果集中每條記錄的順序問題),這一性質剛好可以用來確定結果集的唯一識別碼。當然,簡單地把整個sql語句作為結果集標識符是不可取的,一個顯而易見的理由是,未經處理的sql查詢語句均包含若干空格,而Redis的鍵是不允許存在空格的。這時,我們需要一個可以把sql語句轉換為唯一識別碼的函數。通常,這一功能由散列函數完成,包括MD5,SHA系列等加密散列函數在內的很多演算法均可達到這一目的。
確定結果集標識符之後,從Redis讀資料或向Redis寫資料的思路就很清晰了。對於一個sql語句格式的資料請求,首先計算該語句的MD5並據此得到結果集標識符,然後利用該標識符在Redis中尋找該結果集。注意,結果集中的每一行都有一個相應的鍵,這些鍵都儲存在一個Redis集合結構中。這個集合恰好對應了所需的結果集,所以,該集合的鍵必須包含結果集標識符。如果Redis中不存在這樣一個集合,說明要找的結果集不在Redis中,所以需要執行相應的sql語句,在Mysql中查詢到相應的結果集,然後按照上面所說的辦法把結果集中的每一行以字串或雜湊的形式存入Redis。在Redis中尋找相應結果集的代碼如下:
// 該函數根據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; string resultset_id = md5(sql); // 計算sql語句的md5,這是唯一標識結果集的關鍵 // 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中的排序和分頁問題。
初學Redis(3)——用Redis作為Mysql資料庫的緩衝