在 ThinkPHP 6 控制器中使用文件锁机制

  1. 创建锁管理类

首先,创建一个锁管理类来处理文件锁:

namespace app\common\service;

use Exception;

class LockManager
{
    private $lockFilePath;
    private $lockFile;

    public function __construct($lockFilePath)
    {
        $this->lockFilePath = $lockFilePath;
    }

    public function __destruct()
    {
        $this->releaseLock();
    }

    public function executeWithLock(callable $callback)
    {
        // 打开锁文件,文件不存在时会自动创建
        $this->lockFile = fopen($this->lockFilePath, 'w+');
        if (!$this->lockFile) {
            throw new Exception("无法打开锁文件");
        }

        try {
            // 尝试获取排他锁(独占锁)
            if (flock($this->lockFile, LOCK_EX)) {
                // 锁定成功后执行关键代码
                $callback();
            } else {
                throw new Exception("无法获取锁");
            }
        } finally {
            // 释放锁
            $this->releaseLock();
        }
    }

    private function releaseLock()
    {
        if ($this->lockFile) {
            flock($this->lockFile, LOCK_UN);
            fclose($this->lockFile);
        }
    }
}
  1. 在控制器中使用锁

在你的控制器中,调用 LockManager 来执行需要加锁的操作:

namespace app\controller;

use app\common\service\LockManager;
use think\Controller;
use think\Request;

class TaskController extends Controller
{
    public function process(Request $request)
    {
        // 定义锁文件的路径
        $lockFilePath = runtime_path() . 'lockfile';

        // 创建 LockManager 实例
        $lockManager = new LockManager($lockFilePath);

        // 执行需要加锁的操作
        try {
            $lockManager->executeWithLock(function() {
                // 执行关键操作
                echo "获取锁成功,执行关键操作\n";
                
                // 模拟长时间操作
                sleep(5);
                
                echo "操作完成,释放锁\n";
            });
        } catch (Exception $e) {
            // 处理异常
            echo "错误: " . $e->getMessage();
        }
    }
}

在服务层中使用锁

如果你希望在服务层中处理锁,可以将锁管理逻辑集成到服务类中,类似于控制器中的使用方式。然后在控制器中调用这个服务来处理业务逻辑。

总结

  • 将锁管理逻辑封装到服务类中。
  • 在需要加锁的地方(控制器、服务层等)创建 LockManager 实例并调用 executeWithLock 方法来执行需要加锁的操作。

这样,可以确保在执行关键操作时获得独占锁,并在操作完成后释放锁。

posted @ 2024-08-10 15:03  xingduo  阅读(46)  评论(0编辑  收藏  举报