使用 ThinkPHP 实现简单的缓存锁
在开发过程中,为了避免重复提交等问题,我们常常需要使用缓存锁来控制并发访问。本文将介绍如何利用 ThinkPHP 框架实现一个简单的缓存锁功能。
锁 Key 的生成
在实现缓存锁之前,首先需要确定锁的唯一标识,这里我们采用了学生 ID 和费用数据 ID 来生成锁的唯一 Key。代码如下:
$lockKey = 'pay:StudentId:' . $this->student_id . 'feeDataId:' . $id;
判断是否已经锁定
在获取锁之前,我们需要先判断当前 Key 是否已经被锁定。如果已经锁定,则需要等待一段时间后再尝试获取锁,这里我们设置等待时间为 30 秒。代码如下:
$lock = LockUtils::isLock($lockKey);
if ($lock) {
throw new BusinessException(Code::PARAM_ERROR, '请勿重复提交,30秒后再试');
}
锁定
获取锁成功后,我们需要进行锁定操作。这里我们使用了一个自定义的 LockUtils 类来实现锁的操作,其中包括了锁定和判断是否锁定的方法。具体代码如下:
use app\common\utils\LockUtils;
LockUtils::lock($key, int $time = 30): void;
use app\common\utils\LockUtils;
LockUtils::isLock($key): bool;
LockUtils 类的实现
下面是 LockUtils 类的具体实现,它利用了 ThinkPHP 框架的缓存功能来实现锁的操作:
<?php
declare (strict_types=1);
namespace app\common\utils;
use think\facade\Cache;
class LockUtils
{
/**
* 锁定
* @param string $key 锁的唯一标识
* @param int $time 锁定时长,默认为 30 秒
* @return void
*/
public static function lock(string $key, int $time = 30): void
{
Cache::set($key, 'lock', $time);
}
/**
* 判断是否锁定
* @param string $key 锁的唯一标识
* @return bool
*/
public static function isLock(string $key): bool
{
$lock = Cache::get($key);
return $lock ? true : false;
}
}
以上就是利用 ThinkPHP 实现简单的缓存锁的方法。通过合理的使用缓存锁,我们可以有效地控制并发访问,提高系统的稳定性。
下面是有上下文的具体使用的支付提交代码
$fee = $feeModel->where('id', $feeData->fee_id)
->where('status', 1)
->find();
if (!$fee) {
throw new BusinessException(Code::PARAM_ERROR, '缴费项目不存在/已结束/已取消');
}
// 缴费金额 (分)
$money = $feeData->money * 100;
if (empty($money) || $money <= 0) {
throw new BusinessException(Code::PARAM_ERROR, '缴费金额错误');
}
// 锁Key
$lockKey = 'pay:StudentId:' . $this->student_id . 'feeDataId:' . $id;
// 判断是否已经锁定
$lock = LockUtils::isLock($lockKey);
// 已经锁定,则等待30秒
if ($lock) {
throw new BusinessException(Code::PARAM_ERROR, '请勿重复提交,30秒后再试');
}
// 锁定
LockUtils::lock($lockKey);
// 缴费ID
$fee_data_id = $feeData->id;
// 订单号
$order_no = StrUtils::generateTradeNo();
回调接收部分