deepseektest/extend/traits/CacheTrait.php
2025-03-06 08:59:31 +08:00

204 lines
5.4 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace traits;
use bw\Redis;
/**
* 缓存
*/
trait CacheTrait
{
private $cache_lock_error_msg = "获取锁失败!";
private $cache_lock_thorws_excption = true;
public function setCacheLockThorwsExcption($cache_lock_thorws_excption){
$this->cache_lock_thorws_excption = $cache_lock_thorws_excption;
return $this;
}
public function getCacheLockThorwsExcption(){
return $this->cache_lock_thorws_excption;
}
public function hasRedis($is_interrupt = false) {
$error_msg = '';
try {
$redis = $this->getRedis();
// 检测连接是否正常
$redis->ping();
} catch (\BadFunctionCallException $e) {
// 缺少扩展
$error_msg = $e->getMessage() ? $e->getMessage() : "缺少 redis 扩展";
} catch (\RedisException $e) {
// 连接拒绝
\think\Log::write('redis connection redisException fail: ' . $e->getMessage());
$error_msg = $e->getMessage() ? $e->getMessage() : "redis 连接失败";
} catch (\Exception $e) {
// 异常
\think\Log::write('redis connection fail: ' . $e->getMessage());
$error_msg = $e->getMessage() ? $e->getMessage() : "redis 连接异常";
}
if ($error_msg) {
if ($is_interrupt || $this->cache_lock_thorws_excption) {
throw new \Exception($error_msg);
} else {
$this->setCacheLockErrorMsg($error_msg);
return false;
}
}
return true;
}
public function getRedis() {
if (!isset($GLOBALS['SPREDIS'])) {
$GLOBALS['SPREDIS'] = (new Redis())->getRedis();
}
return $GLOBALS['SPREDIS'];
}
public function getLock($key, $suffix = "-lock-suffix", $timeout = 120, $lock_num = 1) {
$this->hasRedis(true);
$redis = $this->getRedis();
$hashKey = $key . $suffix;
if ($lock_num == 1) { // 单令牌
$nxLock = $redis->set($hashKey, 1, ['nx', 'ex' => $timeout]);
if ($nxLock == 1) {
return true;
} else {
if ($this->cache_lock_thorws_excption) {
throw new \Exception($this->cache_lock_error_msg);
} else {
return false;
}
}
} else {
// 多令牌
$lua = 'local hash_key = KEYS[1]
local max_tokens = tonumber(ARGV[3])
local token_value = ARGV[1]
local token_timeout = tonumber(ARGV[2])
-- 获取当前令牌数
local current_value = redis.call("hget", hash_key, "count")
if not current_value then
-- 锁不存在,初始化锁并设置过期时间
redis.call("hset", hash_key, "count", 1)
redis.call("expire", hash_key, token_timeout)
return 1
else
-- 锁存在,增加计数器
local new_value = tonumber(current_value) + 1
if new_value > max_tokens then
return 0
else
redis.call("hset", hash_key, "count", new_value)
redis.call("expire", hash_key, token_timeout)
return new_value
end
end';
$result = $redis->eval($lua, [$hashKey, $timeout, $lock_num], 1);
if ($result >= 1 && $result <= $lock_num) {
return true;
} else {
if ($this->cache_lock_thorws_excption) {
throw new \Exception($this->cache_lock_error_msg);
} else {
return false;
}
}
}
}
public function setCacheLockErrorMsg($cache_lock_error_msg){
$this->cache_lock_error_msg = $cache_lock_error_msg;
return $this;
}
public function getCacheLockErrorMsg(){
return $this->cache_lock_error_msg;
}
public function freeLock($key, $suffix = "-lock-suffix", $lock_num = 1, $timeout = 120) {
$this->hasRedis(true);
$redis = $this->getRedis();
if (!$key || !$suffix) return true;
$hashKey = $key . $suffix;
if ($lock_num == 1) { // 单令牌
// 执行lua脚本确保删除锁是原子操作
$lua = 'if redis.call("get", KEYS[1]) == ARGV[1]
then
return redis.call("del", KEYS[1])
else
return 0
end';
$result = $redis->eval($lua, [$hashKey, 1], 1);
if ('1' == $result) {
return true;
}
return false;
} else { // 多令牌
$lua = 'local hash_key = KEYS[1]
local token_value = ARGV[1]
local token_timeout = tonumber(ARGV[2])
-- 获取当前令牌数
local current_value = redis.call("hget", hash_key, "count")
if not current_value then
-- 锁不存在,无需释放
return 0
else
-- 锁存在,减少计数器
local new_value = tonumber(current_value) - 1
if new_value < 1 then
-- 计数器小于1删除锁
local result = redis.call("del", hash_key)
return result
else
-- 计数器大于等于1更新锁
redis.call("hset", hash_key, "count", new_value)
redis.call("expire", hash_key, token_timeout)
return new_value
end
end';
$result = $redis->eval($lua, [$hashKey, $timeout, $lock_num], 1);
if ($result >= 1 && $result <= $lock_num) {
return true;
} else {
return false;
}
}
}
}