使用hiredis实现redis分布式锁

蹲街弑〆低调 提交于 2019-11-26 06:15:01

简言

1. redis实现分布式锁的原理,这里不再赘述,不清楚的可以参见笔者的这篇博客

https://blog.csdn.net/yzf279533105/article/details/100524700

2. 解锁时使用lua脚本,由于hiredis是根据空格来解析cmd参数的,但是lua中肯定有空格,所以解锁的redis命令要分开格式化

 

代码如下:

头文件(仅贴出主要代码)

// redis锁
struct RedisLock
{
	string 		key;		// 锁的key
	int 		randval;	// 随机值
};


// 	加锁(锁数据,过期时间,单位:秒)
bool Lock(RedisLock lockkey, uint32_t expire);

// 解锁
bool Unlock(RedisLock lockkey);

cpp文件

// 	加锁(锁数据,过期时间,单位:秒)
bool CRedisClient::Lock(RedisLock lockkey, uint32_t expire)
{
	bool bSuc = connect();
	if (!bSuc) 
	{
		ERROR("CRedisClient::Lock(), connect failed");
		return false;
	}

	ostringstream os;
	os<< "set " << lockkey.key <<" "<< lockkey.randval << " ex " << expire << "  nx";

	// set命令
	CAutoRedisReply autoR;
	redisReply* r = (redisReply*)redisCommand(m_redisCtx, os.str().c_str());
	if (NULL == r) 
	{
		ERROR("CRedisClient::Lock(),call redisCommand() error,command=%s, redis break connection,m_redisCtx: %p",os.str().c_str(), m_redisCtx);
		m_bConnected = false;
		return false;
	}
	autoR.set(r);

	if (r->type!=REDIS_REPLY_STATUS || r->str==NULL || strcasecmp(r->str, "OK") != 0)
	{
		ERROR("CRedisClient::Lock(),result error, type=%d, command=%s, errmsg=%s", r->type, os.str().c_str(), r->str);
		return false;
	}

	return true;
}

// 解锁
bool CRedisClient::Unlock(RedisLock lockkey)
{
	// 注意:由于hiredis是根据空格来解析cmd参数的,但是lua中肯定有空格,所以这里的命令要分开格式化;不要像上面的那样直接用ostringstream来合成所有的字符串
	char script[256] = {0};
	sprintf(script, "if redis.call('get', KEYS[1]) == '%d' then return redis.call('del', KEYS[1]) else return 0 end", lockkey.randval);

	CAutoRedisReply autoR;
	// 注意命令格式,不要把参数key格式化到script中,那样会报参数个数不够的错误
	redisReply* r = (redisReply*)redisCommand(m_redisCtx, "eval %s 1 %s", script, lockkey.key.c_str());
	if (NULL == r) 
	{
		ERROR("CRedisClient::Lock(),call redisCommand() error,command=%s, redis break connection,m_redisCtx: %p",script, m_redisCtx);
		m_bConnected = false;
		return false;
	}
	autoR.set(r);

	if (r->type!=REDIS_REPLY_INTEGER || r->integer!= 1 || r->str != NULL)
	{
		ERROR("CRedisClient::Lock(),result error, type=%d, command=%s, r->interger=%d, errmsg=%s", r->type, script, r->integer, r->str);
		return false;
	}

	return true;
}

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!