使用hiredis实现redis分布式锁

简言

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

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

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

3. 重点关注 Unlock()函数即可,关注里面如何调用lua脚本的

代码如下:

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

// 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;
}
发布了105 篇原创文章 · 获赞 58 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/yzf279533105/article/details/103240216