① 调用自身编程语言提供的文件锁。
适合单机业务量不大的系统,业务量太大,文件系统就会频现资源占用。
/**
* 同步锁
* @param 锁标识
* @return
*/
function _Lock($file = "lock")
{
// 父目录一定要设置为777
$file = "./lock/{$file}.txt";
$fp = fopen($file, 'w');
flock($fp, LOCK_EX);
return $fp;
}
/**
* 解除同步锁
* @param $fp 通过_Lock函数返回的id
*/
function _UnLock($fp)
{
flock($fp, LOCK_UN);
fclose($fp);
}
② 数据库锁 借助数据库字段唯一性特征 保证插入数据不重复
/**
* 全局事务锁
* @param string $key 钥匙,30 字符内
*/
function lock($key)
{
DB::query("insert into locks (`key`, created_at) values ('" . addslashes($key) . "', " . time() . ")");
}
/**
* 解除全局事务锁
* @param string $key 钥匙,30 字符内
*/
function unlock($key)
{
DB::query("delete from locks where `key`='" . addslashes($key) . "'");
}
在以接口外的业务中 可以在返回数据前注册回调业务 做解锁操作
/**
* 延迟函数
* @param Closure|string $fn
*/
function defer($fn)
{
global $_G;
$_G['__LAST_DEFERS__'][] = $fn;
}
lock('REFUND-'.$order['id']);
defer(function () {
unlock('REFUND-'.$order['id']);
});
//TODO 你的退款业务 一旦报错 在defer 里解锁
数据库锁结构
CREATE TABLE `locks` (
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`key` char(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`created_at` int(10) UNSIGNED NOT NULL,
`updated_at` int(10) UNSIGNED NOT NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `key`(`key`) USING BTREE,
INDEX `created_at`(`created_at`) USING BTREE
) ENGINE = InnoDB ;
③ DZ 进程锁
同时支持数据库锁和内存锁并优化了同进程多次加锁的优化
更多详情看 https://blog.csdn.net/enough_br/article/details/7303500
if(!discuz_process::islocked($processname, 600)) {
// TODO 你的业务
discuz_process::unlock($processname);
}
// 支持自动解锁 在应用结束时解锁
if(!discuz_process::islocked($processname, 600,1)) {
// TODO 你的业务 会自动解锁
}
PHP 实现类 discuz_process.php
PHP 数据库模型 table_common_process
PHP 数据库结构
CREATE TABLE `pre_common_process` (
`processid` char(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`expiry` int(10) NULL DEFAULT NULL,
`extra` int(10) NULL DEFAULT NULL,
PRIMARY KEY (`processid`) USING BTREE,
INDEX `expiry`(`expiry`) USING BTREE
) ENGINE = InnoDB ;
④ redis 内存锁