• 0
  • 0

PHP 业务加锁实现

2021-09-04 768 0 admin 所属分类:PHP 记录

① 调用自身编程语言提供的文件锁。

适合单机业务量不大的系统,业务量太大,文件系统就会频现资源占用。

/**
 * 同步锁
 * @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 内存锁


返回顶部