接上文同步锁(用文件实现)
用文件的形式实现同步锁,需要对应目录有读写权限,有IO性能消耗,而且会生成残留文件, 其实也可以借助redis达到同样的效果
Redis是线程安全的,可以把Redis看成单线程的模型.
首先来看Redis的set命令
原生命令如下
set key value [EX seconds] [PX milliseconds] [NX|XX]
参数说明
*key
*value
*[EX seconds] 可选,过期时间 单位秒
*[PX milliseconds] 可选,过期时间 单位毫秒
*[NX|XX] 可选,NX表示key不存在时执行set命令
XX表示key存在时执行set命令
来个例子实验一下
设置name->zhangsan
过期时间20秒,且内存中不存在名为name的key时,命令执行
127.0.0.1:6379> set name zhangsan EX 20 NX
执行两遍相同命令,只有第一条返回OK
image.png
PHP实现
用composer 下载Redis三方包,不同的包操作可能会有些差异.
我用的是Predis
namespace lock;
require_once 'lib/vendor/autoload.php';
use \Predis\Client;
class RedisLock
{
private $client;
private $key;
/**
* RedisLock constructor.
*
* @param $key
*/
public function __construct ($key) {
\Predis\Autoloader::register();
$client = new Client([
'scheme' => 'tcp',
'host' => '127.0.0.1',
'port' => 6379,
]);
$this->client = $client;
$this->key = $key;
}
/**
* 获取锁
*
* @return mixed
*/
function getLock(){
return $this->client->set($this->key,1,'EX',10,'NX');
}
/**
* 清除锁
*/
function clearLock(){
$this->client->del($this->key);
}
}
测试
use lock\RedisLock;
require_once 'RedisLock.php';
if (!isset($argv[1])){
echo '输入cacheKey';
return;
}
//获取输入的cacheKey
$cacheKey = $argv[1];
$redisLock = new RedisLock($cacheKey);
if($redisLock->getLock())
{
echo "读库-$cacheKey".PHP_EOL;
sleep(60);
//TODO 设置缓存
$redisLock->clearLock();
}else{
echo "获取锁失败$cacheKey";
}
效果
image.png
image.png
确保只有一个线程进入读取数据库的代码段.就能避免缓存击穿问题.