最近事情比较少,随便整理一下之前写的一些可以挪用到其他项目的小功能,之前一个项目接入企业微信加好友的接口,回调的时候存在重复回调的问题,所以加了一个redis锁解决问题:
实现思路与注意事项:
设置合理的过期时间,解决忘记释放锁、甚至服务器宕机未释放锁的问题
获取锁和设置过期时间,需要具有原子性,使用指令
SET key value NX PX milliseconds
NX 代表只有当键key不存在的时候才会设置key的值
PX 表示设置键 key 的过期时间,单位是毫秒
- value 值随机设置,删除 value 前判断是否相等,解决当前线程可能释放其他线程加的锁的问题
- lua 脚本可以解决,删除 value 时判断-删除,非原子操作的问题
项目的代码 放在公用目录function.php:
/**
* redis 锁
* @param $cacheKey
* @return bool
*/
function set_redis_lock($cacheKey): bool
{
$redis = make(Redis::class);
$result = $redis->setnx($cacheKey, 1);
$redis->expire($cacheKey, 600);
return $result;
}
/**
* 删除锁
* @param $cacheKey
* @return int
*/
function del_redis_lock($cacheKey): int
{
return make(Redis::class)->del($cacheKey);;
}
回调业务中的代码示例:
$cacheKey = 'wechatFissionNumber:'.$helpId;
if (!set_redis_lock($cacheKey)) return []; //如果存在不执行后面的业务处理
try {
...里面是不可看内容
} catch (\Throwable $t) {
wlog($this->logPath, '异常msg:' . $t->getMessage() . PHP_EOL);
return [];
} finally {
del_redis_lock($cacheKey); //处理完业务,释放锁
}