2019-06-21周报
<h2>redis锁</h2>
<p>一种为了避免access_token过期时,处理并发请求时用到的redis锁</p>
<p><strong>需要用到的redis缓存</strong>
锁标志:$lock = string:{action_name}:access_token:lock
access_token储存:$accessToken = string:{action_name}:access_token</p>
<p><strong>设计思路</strong>
当需要刷新access_token时,先使用Redis的setnx写入锁并expire过期时间,写入成功则继续往下执行access_token获取方法,获取access_token后写入缓存$accessToken,再将锁删除;如果写锁失败,检测获取$accessToken,获取到值返回,否则返回再次尝试拿锁。
<img src="https://www.showdoc.cc/server/api/common/visitfile/sign/57d22526205d253fb24d136be2671a16?showdoc=.jpg" alt="" /></p>
<pre><code>public function refreshToken()
{
$redis = Redis::connection();
$redis->del($this->redisKey['access_token']); //删除原access_token
$times = 0;
while ($times < 20) { //设置循环时间大于锁的生命,如果并发时前几次请求失败,后面还可以续上
$setLock = $redis->setnx($this->redisKey['access_token_lock'], 1); //写锁
if ($setLock) { //写锁成功,发起请求
$redis->expire($this->redisKey['access_token_lock'], 5); //设置锁的生命,如果本次请求失败,才能解锁进行下一次锁操作
$accessToken = FUNCTION::requestAccessToken(); //请求接口
if ($accessToken) $redis->setex($this->redisKey['access_token'], EXPIRETIME, $accessToken); //成功获取到access_token后,写入缓存
return $accessToken;
}
$accessToken = $redis->get($this->redisKey['access_token']); //检测是否已有可用access_token
if ($accessToken) return $accessToken;
usleep(500000);
$times++;
}
return false;
}</code></pre>
<h3>虽然这种方式比较符合业务情况,但是对redis锁来说没有活用性,因此把锁独立出来,可以供多处使用</h3>
<p>一个业务要拿到<strong>锁的名称</strong>后才能继续往下执行,<strong>当业务完成后,记得删锁</strong></p>
<pre><code class="language-php">public function redisLock($redisKey)
{
$times = 0;
while ($times < 2000) {
$setLock = $this->redis->setnx($redisKey . '_lock', 1);
if ($setLock) {
$this->redis->expire($redisKey . '_lock', 10);
return $redisKey . '_lock';
}
usleep(5000);
$times++;
}
return false;
}</code></pre>
<h2>MongoDB</h2>
<p>文档:<a href="https://docs.mongodb.com/manual/reference/command/">https://docs.mongodb.com/manual/reference/command/</a>
<strong>实例化链接</strong></p>
<p><code>$this->mongoManage = new \MongoDB\Driver\Manager("mongodb://username:password@127.0.0.1:20000/database")</code></p>
<p><strong>直接执行commonds来进行aggregate(聚合)、count(计数)、group(分组)、distinct(去重)等操作</strong></p>
<pre><code class="language-php">//$command:需要执行的命令
public function command($command)
{
$commandObj = new \MongoDB\Driver\Command($command);
$cursor = $this->mongoManage->executeCommand($this->config['mongo_db'], $commandObj);
return $cursor->toArray();
}</code></pre>
<p><strong>collections筛选commands</strong></p>
<pre><code class="language-php">$command = [
'listCollections' => 1,
'filter' => ['name' => ['$regex' => $tableKey]],
];
$result = $this->command($command);</code></pre>
<p>当使用aggregate的commands时,如果要用到$match筛选,务必把$match放在0位</p>