Redis Eval的c++封装

Redis Eval使用好处

  • Redis使用eval可以执行lua脚本,使得程序的灵活性更好。
  • 打包命令执行,减少网络开销,evalsha更小的参数数据传输。
  • 原子操作

Redis Eval的c++封装

更新 方案二 (redisCommandArgv)


	redisContext* redisCon;
	std::map <std::string, std::string> _map_script_sha;
	
	bool ScriptLoad(const std::string &luascript, std::string &sha)
	{
		if (!redisCon)
		{
			return false;
		}

		bool flag = false;
		redisReply *reply = (redisReply *)redisCommand(redisCon, "SCRIPT Load  %s ", luascript.c_str());
		if (NULL != reply)
		{
			if (reply->type == REDIS_REPLY_STRING) {
				sha = reply->str;
				flag = true;
				_map_script_sha[luascript] = sha;
			}
			freeReplyObject(reply);
		}

		return flag;
	}

	bool RunCommand(std::vector<std::string> cmd)
	{
		redisReply *r = nullptr;
		bool ret = RunCommand(cmd, r);
		freeReplyObject(r);
		return ret;
	}

	bool RunCommand(std::vector<std::string> cmd, redisReply *& r)
	{
		std::vector<const char*> argv;
		std::vector<unsigned int> argvlen;

		for (const auto &str : cmd) {
			argv.push_back(str.c_str());
			argvlen.push_back(str.length());
		}

		r = (redisReply *)redisCommandArgv(redisCon, argv.size(), &(argv[0]), &(argvlen[0]));
		if (NULL == r) {
			return false;
		}
		else if (r->type == REDIS_REPLY_ERROR) {
			std::cout << r->str << std::endl;
			//goto funcend;
		}
		return true;
	}

	bool Eval(const std::string& luascript, int numkeys, const std::vector<std::string> vec_key, const  std::vector<std::string> vec_value, redisReply *& r) {
		std::vector<std::string> cmd;
		cmd.push_back("EVAL");
		cmd.push_back(luascript);
		cmd.push_back(std::to_string(numkeys));
		cmd.insert(cmd.end(), vec_key.begin(), vec_key.end());
		cmd.insert(cmd.end(), vec_value.begin(), vec_value.end());

		bool ret = RunCommand(cmd, r);
		return ret;
	}

	bool Eval(const std::string& luascript, int numkeys, const std::vector<std::string> vec_key, const  std::vector<std::string> vec_value) {
		redisReply * r = nullptr;
		bool ret = Eval(luascript, numkeys, vec_key, vec_value, r);
		freeReplyObject(r);
		return ret;
	}

	bool EvalSha(const std::string& luascript, int numkeys, const std::vector<std::string> vec_key, const  std::vector<std::string> vec_value, redisReply *& r) {
		std::string sha1 = _map_script_sha[luascript];
		if (sha1 == "" && !ScriptLoad(luascript, sha1))
		{
			return false;
		}

		bool ret = false;

		auto evalfuc = [&]() {
			std::vector<std::string> cmd;
			cmd.push_back("EVALSHA");
			cmd.push_back(sha1);
			cmd.push_back(std::to_string(numkeys));
			cmd.insert(cmd.end(), vec_key.begin(), vec_key.end());
			cmd.insert(cmd.end(), vec_value.begin(), vec_value.end());
			ret = RunCommand(cmd, r);
		};

		evalfuc();

		if (NULL != r && r->type == REDIS_REPLY_ERROR
			&& std::string(r->str) == "NOSCRIPT No matching script. Please use EVAL.")
		{
			freeReplyObject(r);
			if (ScriptLoad(luascript, sha1)) {
				evalfuc();
			}
			else {
				return false;
			}
		}
		return ret;
	}

	bool EvalSha(const std::string& luascript, int numkeys, const std::vector<std::string> vec_key, const  std::vector<std::string> vec_value) {
		redisReply * r = nullptr;
		bool ret = EvalSha(luascript, numkeys, vec_key, vec_value, r);
		freeReplyObject(r);
		return ret;
	}

	bool ScriptFlush()
	{
		bool flag = false;
		redisReply *reply = (redisReply *)redisCommand(redisCon, "SCRIPT FLUSH");
		if (NULL != reply)
		{
			if (std::string(reply->str) == "OK") {
				flag = true;
				_map_script_sha.clear();
			}
			freeReplyObject(reply);
		}

		return flag;
	}

方案一 (redisCommand)

bool ScriptLoad(const std::string &luascript, std::string &sha)
	{
		if (!redisCon)
		{
			return false;
		}

		bool flag = false;
		redisReply *reply = (redisReply *)redisCommand(redisCon, "SCRIPT Load  %s ", luascript.c_str());
		if (NULL != reply)
		{
			if (reply->type == REDIS_REPLY_STRING) {
				sha = reply->str;
				flag = true;
				map_script_sha[luascript] = sha;
			}
			freeReplyObject(reply);
		}

		return flag;
	}

	bool ScriptExist(const std::string &sha)
	{
		if (!redisCon)
		{
			return false;
		}

		bool flag = false;

		redisReply *reply = (redisReply *)redisCommand(redisCon, "SCRIPT EXISTS %s ", sha.c_str());
		if (NULL != reply)
		{
			if (reply->type == REDIS_REPLY_ARRAY && reply->elements>0) {
				redisReply *item1 = reply->element[0];
				if (item1 && item1->type == REDIS_REPLY_INTEGER && item1->integer == 1)
				{
					flag = true;
				}
			}
			freeReplyObject(reply);
		}

		return flag;
	}

	std::map <std::string, std::string> map_script_sha;

	template<typename... T>
	bool EvalEx(const std::string& luascript, int numkeys, std::string format, T... args)
	{
		if (!redisCon)
		{
			return false;
		}
		bool flag = false;

		std::string sha1 = map_script_sha[luascript];

		if(sha1==""&& !ScriptLoad(luascript,sha1))
		{
			return false;
		}

		std::string totalFormat = "evalsha %s %d " + format;
		redisReply *reply = (redisReply *)redisCommand(redisCon, totalFormat.c_str(), sha1.c_str(), numkeys, args...);
		if (NULL != reply && reply->type == REDIS_REPLY_ERROR
			&& std::string(reply->str) == "NOSCRIPT No matching script. Please use EVAL.")
		{
			freeReplyObject(reply);
			if (ScriptLoad(luascript, sha1)) {
				reply = (redisReply *)redisCommand(redisCon, totalFormat.c_str(), sha1.c_str(), numkeys, args...);
			}
			else {
				return false;
			}
		}
		if (NULL != reply) {
			if (reply->type != REDIS_REPLY_ERROR)
			{
				flag = true;
			}
			freeReplyObject(reply);
		}

		return flag;
	}

	template<typename... T>
	bool EvalEx(redisReply *&p_reply, const std::string& luascript, int numkeys, std::string format, T... args)
	{
		if (!redisCon)
		{
			return false;
		}
		bool flag = false;

		std::string sha1 = map_script_sha[luascript];

		if (sha1 == "" && !ScriptLoad(luascript,sha1))
		{
			return false;
		}

		std::string totalFormat = "evalsha %s %d " + format;
		redisReply *reply = (redisReply *)redisCommand(redisCon, totalFormat.c_str(), sha1.c_str(), numkeys, args...);
		if (NULL != reply && reply->type == REDIS_REPLY_ERROR
			&& std::string(reply->str) == "NOSCRIPT No matching script. Please use EVAL.")
		{
			freeReplyObject(reply);
			if (ScriptLoad(luascript, sha1)) {
				reply = (redisReply *)redisCommand(redisCon, totalFormat.c_str(), sha1.c_str(), numkeys, args...);
			}
			else {
				return false;
			}
		}                                         
		if (NULL != reply) {
			if (reply->type == REDIS_REPLY_ERROR)
			{
				freeReplyObject(reply);
			}
			else {
				flag = true;
				p_reply = reply;
			}
		}

		return flag;
	}

	template<typename... T>
	bool Eval(redisReply *&p_reply,const std::string& luascript, int numkeys, std::string format, T... args)
	{
		if (!redisCon)
		{
			return false;
		}
		bool flag = false;

		std::string totalFormat = "eval %s %d " + format;
		redisReply *reply = (redisReply *)redisCommand(redisCon, totalFormat.c_str(), luascript.c_str(), numkeys, args...);
		if (NULL != reply)
		{
			if (reply->type == REDIS_REPLY_ERROR)
			{
				freeReplyObject(reply);
			}
			else {
				flag = true;
				p_reply = reply;
			}
		}

		return flag;
	}

	template<typename... T>
	bool Eval(const std::string& luascript, int numkeys, std::string format, T... args)
	{
		if (!redisCon)
		{
			return false;
		}
		bool flag = false;

		std::string totalFormat = "eval %s %d " + format;
		redisReply *reply = (redisReply *)redisCommand(redisCon, totalFormat.c_str(), luascript.c_str(), numkeys, args...);
		if (NULL != reply)
		{
			if (reply->type != REDIS_REPLY_ERROR)
			{
				flag = true;
			}
			freeReplyObject(reply);
		}

		return flag;
	}

附带说明

  • EvalEx主要是调用的evalsha命令,本来是想用ScriptExist来判断脚本是否已经加载(存在),但是考虑到如果每次调用都执行ScriptExist的话,确实对于程序的性能是一种浪费,于是改成直接调用evalsha,如果脚本不存在的话,会报一个特定的错误NOSCRIPT No matching script. Please use EVAL.,以此来提高运行效率。
		EvalEx("redis.call('set', KEYS[1],  ARGV[1])", 1, "%s %d", "string8", 9);
		redisReply *p_reply = NULL;
		EvalEx(p_reply, "redis.call('set', KEYS[1],  ARGV[1])", 1, "%s %d", "string7", 3);
		if (p_reply) {
			freeReplyObject(p_reply);
		}
		Eval("redis.call('set', KEYS[1],  ARGV[1])", 1, "%s %d", "string8", 9);
		redisReply *p_reply = NULL;
		Eval(p_reply, "redis.call('set', KEYS[1],  ARGV[1])", 1, "%s %d", "string7", 3);
		if (p_reply) {
			freeReplyObject(p_reply);
		}
  • Eval 和 EvalEx都有两个版本,一个关心lua脚本的返回值的,一个不关心的。如果需要获取lua脚本返回值的话,需要传入redisReply指针,但是要注意需要自己释放销毁指针,不然会发生内存泄漏。
  • 如果想要获取多个lua脚本返回值。需要以table的形式返回。
local a = 1
local b = "str"
return {a, b}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值