local key = KEYS[1]
local value = KEYS[2]
local ttl = KEYS[3]
local ok = redis.call('setnx', key, value)
if ok == 1 then
redis.call('expire', key, ttl)
end
return ok
<pre class="wp-block-syntaxhighlighter-code">
<?php
$ok = $redis->set($key, $value, array('nx', 'ex' => $ttl));
if ($ok) {
// 业务逻辑代码
$redis->del($key);
}
?>
</pre>
<pre class="wp-block-syntaxhighlighter-code">
<?php
$ok = $redis->set($key, $random, array('nx', 'ex' => $ttl));
if ($ok) {
// 业务逻辑代码
if ($redis->get($key) == $random) {
$redis->del($key);
}
}
?>
</pre>
<pre class="wp-block-syntaxhighlighter-code">
<?php
namespace common\logics\redis;
use Yii;
/**
* This is the model class for table "{{%lock}}".
*
* @author Qiang Wang <shuijingwanwq@163.com>
* @since 1.0
*/
class Lock extends \yii\redis\ActiveRecord
{
/**
* Redis模型的锁定实现
* @param string $lockKeyName 锁定键名
* 格式如下:
*
* 'game_category' //锁定键名,如比赛分类
*
* @param int $timeOut Redis锁定超时时间,单位为秒
* 格式如下:3
*
* @return bool 成功返回真/失败返回假
* 格式如下:
*
* true //状态,获取锁定成功,可继续执行
*
* 或者
*
* false //状态,获取锁定失败,不可继续执行
*
*/
public function lock($lockKeyName, $timeOut = 3)
{
// 设置锁定的过期时间,获取相关锁定参数
$time = time();
$lockKey = Yii::$app->params['redisLock']['keyPrefix'] . $lockKeyName;
$lockExpire = $time + $timeOut;
// 获取 Redis 连接,以执行相关命令
$redis = Yii::$app->redis;
// 获取锁定
$executeCommandResult = $redis->setnx($lockKey, $lockExpire);
// 返回0,表示已经被其他客户端锁定
if ($executeCommandResult == 0) {
// 防止死锁,获取当前锁的过期时间
$lockCurrentExpire = $redis->get($lockKey);
// 判断锁是否过期,如果已经过期
if ($time > $lockCurrentExpire) {
// 防止并发锁定,检查存储在 key 的旧值是否仍然是过期的时间戳,如果是,则获取锁定,否则返回假
$executeCommandResult = $redis->getset($lockKey, $lockExpire);
if ($lockCurrentExpire != $executeCommandResult) {
return false;
}
}
// 返回0,表示已经被其他客户端锁定,且不存在死锁,返回假
if ($executeCommandResult == 0) {
return false;
}
}
return true;
}
/**
* 判断Redis模型的锁定是否存在
* @param string $lockKeyName 锁定键名
* 格式如下:
*
* 'game_category' //锁定键名,如比赛分类
*
* @return bool 锁定是否存在
* 格式如下:
*
* true //状态:已存在
*
* 或者
*
* false //状态:不存在
*
*/
public function isLockExist($lockKeyName)
{
// 获取相关锁定参数
$time = time();
$lockKey = Yii::$app->params['redisLock']['keyPrefix'] . $lockKeyName;
// 获取 Redis 连接,以执行相关命令
$redis = Yii::$app->redis;
// 获取锁定
$executeCommandResult = $redis->get($lockKey);
// 返回NULL,表示不存在锁定,否则表示存在
if ($executeCommandResult === null) {
return false;
} else {
// 如果存在锁定,判断锁是否过期,如果已经过期,则仍然认定为不存在锁定
if ($time > $executeCommandResult) {
// 如果已经过期,则释放锁定
$redis->del($lockKey);
return false;
}
}
return true;
}
/**
* Redis模型的释放锁定实现
* @param string $lockKeyName 锁定键名
* 格式如下:
*
* 'game_category' //锁定键名,如比赛分类
*
* @return integer 被删除的keys的数量
* 格式如下:
*
* 1 //被删除的keys的数量
*
* 或者
*
* 0 //被删除的keys的数量
*
*/
public function unlock($lockKeyName)
{
// 获取相关锁定参数
$lockKey = Yii::$app->params['redisLock']['keyPrefix'] . $lockKeyName;
// 获取 Redis 连接,以执行相关命令
$redis = Yii::$app->redis;
// 释放锁定
return $redis->del($lockKey);
}
}
</pre>
SET命令加上选项已经可以完全取代SETNX, SETEX, PSETEX的功能,所以在将来的版本中,redis可能会不推荐使用并且最终抛弃这几个命令。如图1

需要长期技术维护或远程问题排查?
我是拥有 15+ 年经验的 PHP / Go 后端工程师,长期关注已有系统维护、Bug 修复、性能优化、服务器排查、WordPress 网站维护和小功能迭代。
如果你的项目遇到以下情况,可以先从一次小问题排查开始合作:
- ✅ PHP / Laravel / Yii2 老项目无人维护
- ✅ Go / Gin 后端接口需要排查或优化
- ✅ WordPress 网站访问慢、报错或插件冲突
- ✅ Nginx / MySQL / Redis / Linux 服务器异常
- ✅ CDN / Cloudflare / DNS / HTTPS 配置问题
- ✅ 需要长期远程技术支持或兼职维护
更多介绍请查看:关于我 & 合作
微信:13980074657
邮箱:shuijingwanwq@gmail.com
Telegram:@shuijingwan
GitHub:https://github.com/shuijingwan

发表回复