把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中的排序和分页问题。