[奇技Y巧]解决程序缓存锁命名困难,命名冲突问题

平时加锁总是奔波于命名,害怕命名冲突,不规范等问题,于是使用debug_backtrace函数通过调用链搞了一搞,通过file,class,function来确定一个锁的位置,从而解决命名冲突,不规范等问题。(迎喷共近)

局部锁

对一段程序进行加锁,保证该局域环境内或跨进程原子性,如发送短信

public function sendSms(string $phone)
{
    if (! setnxLock($phone, 10)) return false;
    /**
     * 处理逻辑
     */
    delLock($phone);

    return true;
}

全局锁

如一个订单多个地方都在处理,但只能单一处生效

public function handleOrder(string $order_no)
{
    if (! setnxLock($order_no, 10, true)) return false;
    /**
     * 处理逻辑
     */
    delLock($order_no, true);

    return true;
}

获取缓存锁key

string getLockKey($key, true);

整理汇总

方法放在全局方法中,方便全局调用

<?php

use App\Constants\CacheKey;

if (! function_exists('setnxLock')) {
    /**
     * 设置缓存锁
     *
     * @param mixed $key     锁键
     * @param int   $ttl     过期时间
     * @param bool  $global  是否全局锁
     *
     * @return bool
     */
    function setnxLock($key, int $ttl = 5, bool $global = false): bool
    {
        $lock_key = getLockKey($key, $global);

        return redis()->setnx($lock_key, 1) && redis()->expire($lock_key, $ttl);
    }
}

if (! function_exists('delLock')) {
    /**
     * 删除缓存锁
     *
     * @param mixed $key     锁键
     * @param bool  $global  是否全局锁
     *
     * @return bool
     */
    function delLock($key, bool $global = false): bool
    {
        $lock_key = getLockKey($key, $global);

        return redis()->del($lock_key);
    }
}

if (! function_exists('getLockKey')) {
    /**
     * 获取缓存锁
     *
     * @param mixed $key     锁键
     * @param bool  $global  是否全局锁
     *
     * @return string
     */
    function getLockKey($key, bool $global = false): string
    {
        if ($global) return CacheKey::GLOBAL_LOCK_CACHE_KEY . $key;

        return CacheKey::COMMON_LOCK_CACHE_KEY . md5(implode('', lockBacktrace())) . ':' . $key;
    }
}

if (! function_exists('lockBacktrace')) {
    /**
     * 获取调用位置
     * 
     * @return array
     */
    function lockBacktrace(): array
    {
        $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5)[4];
        $file = $backtrace['file'] ?? '';
        $class = $backtrace['class'] ?? '';
        $function = $backtrace['function'] ?? '';

        return compact('file', 'class', 'function');
    }
}

缓存key管理类

class CacheKey extends AbstractConstants
{
    // 系统配置缓存
    const SYSTEM_CONFIG_CACHE_KEY = 'hash:system_config_cache';
    // 全局缓存锁
    const GLOBAL_LOCK_CACHE_KEY = 'string:global_lock:';
    // 普通缓存锁
    const COMMON_LOCK_CACHE_KEY = 'string:common_lock:';
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 1

你可以把加锁和解锁封装成一个类,这样子可能更好一点

2年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!