PHP批量操作加锁
-
对于批量操作进行加锁,防止重复提交和数据库冲突
-
register_shutdown_function() 函数,register_shutdown_function 用于注册一个在脚本执行完毕或发生致命错误时调用的函数。这意味着 register_shutdown_function 注册的函数会在脚本的正常执行流程结束后调用,而不是立即执行。代码的执行顺序如下:
- 注册一个 shutdown 函数,该函数在脚本结束时调用 LockService::remove($lockKey)。
- 执行 $value = 1;。
- 脚本继续执行后续的代码。
- 当脚本执行完毕或发生致命错误时,调用注册的 shutdown 函数。
$lockKey = 'store:pop:plant:operation'.$storeId;
//判断锁是否存在
if (LockService::has($lockKey, 5)) {
$this->error('正在处理,请勿重复提交');
}
//register_shutdown_function
register_shutdown_function(function ($lockKey) {
LockService::remove($lockKey);
}, $lockKey);
LockService服务类
<?php
namespace app\common\service;
class LockService
{
/**
* 判断是否有锁
* @param string $key 锁Key
* @param int $ttl 锁时间(秒)
* @param bool $refreshTtl 是否重置锁时间
* @return bool
* @throws \RedisException
*/
public static function has(string $key, int $ttl = 5, bool $refreshTtl = true): bool
{
$res = RedisService::handle()->incr(self::buildKey($key));
if ($refreshTtl || $res === 1) {
RedisService::handle()->expireAt(self::buildKey($key), time() + $ttl);
}
return $res !== 1;
}
/**
* 移除锁
* @param string $key
* @return void
* @throws \RedisException
*/
public static function remove(string $key)
{
RedisService::handle()->del(self::buildKey($key));
}
/**
* 获取锁定次数
* @param string $key
* @return false|mixed|\Redis|string
* @throws \RedisException
*/
public static function times(string $key)
{
return RedisService::handle()->get(self::buildKey($key));
}
private static function buildKey(string $key): string
{
return 'lock:' . $key;
}
}