接上文同步鎖(用文件實(shí)現(xiàn))
用文件的形式實(shí)現(xiàn)同步鎖,需要對(duì)應(yīng)目錄有讀寫權(quán)限,有IO性能消耗,而且會(huì)生成殘留文件, 其實(shí)也可以借助redis達(dá)到同樣的效果
Redis是線程安全的,可以把Redis看成單線程的模型.
首先來看
Redis的set命令
原生命令如下
set key value [EX seconds] [PX milliseconds] [NX|XX]
參數(shù)說明
*key
*value
*[EX seconds] 可選,過期時(shí)間 單位秒
*[PX milliseconds] 可選,過期時(shí)間 單位毫秒
*[NX|XX] 可選,NX表示key不存在時(shí)執(zhí)行set命令
XX表示key存在時(shí)執(zhí)行set命令
來個(gè)例子實(shí)驗(yàn)一下
設(shè)置name->zhangsan
過期時(shí)間20秒,且內(nèi)存中不存在名為name的key時(shí),命令執(zhí)行
127.0.0.1:6379> set name zhangsan EX 20 NX
執(zhí)行兩遍相同命令,只有第一條返回OK

image.png
PHP實(shí)現(xiàn)
用composer 下載Redis三方包,不同的包操作可能會(huì)有些差異.
我用的是Predis
<?php
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);
}
}
測(cè)試
<?php
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 "讀庫(kù)-$cacheKey".PHP_EOL;
sleep(60);
//TODO 設(shè)置緩存
$redisLock->clearLock();
}else{
echo "獲取鎖失敗$cacheKey";
}
效果
image.png

image.png
確保只有一個(gè)線程進(jìn)入讀取數(shù)據(jù)庫(kù)的代碼段.就能避免緩存擊穿問題.