You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP Slim 3实现端点单请求处理与请求排队方案

解决Slim 3端点并发请求导致的重复插入问题

问题根源

并发请求时,多个请求同时执行SELECT查询,都通过了自定义逻辑判断,随后同时执行INSERT操作,触发数据库唯一键约束,抛出Integrity constraint violation: 1062 Duplicate entry错误。要实现端点串行处理请求,可从数据库层面或应用层面入手。

方案一:数据库事务+行级锁(推荐)

利用数据库事务和SELECT ... FOR UPDATE锁定查询到的行,确保同一时间只有一个请求能获取该行的操作权限,从根源避免并发冲突。

修改后的代码示例:

function addClient($request) {
    $client = json_decode($request->getBody());
    // 给查询语句加上FOR UPDATE,锁定结果行
    $sql = 'SELECT `unique_column` FROM your_table WHERE [查询条件] FOR UPDATE';

    try {
        $db = getConnection();
        $db->beginTransaction(); // 开启事务

        $stmt = $db->prepare($sql);
        $stmt->execute();
        $row = $stmt->fetch(PDO::FETCH_ASSOC);

        if ($row && [some logic]) { // 确保行存在且满足自定义逻辑
            $get_card_query = "INSERT INTO another_table (target_column) VALUES (?)";   
            $stmt = $db->prepare($get_card_query);
            $stmt->bindParam(1, $row['unique_column']);
            $stmt->execute();
        }

        $db->commit(); // 提交事务,释放锁
        $db = null;
    } catch(PDOException $e){
        if (isset($db)) {
            $db->rollBack(); // 出错时回滚事务
        }
        echo '{"error":{"text":'. $e->getMessage() .'}}';
    }
}
  • 核心逻辑:FOR UPDATE会锁定查询到的行,直到事务提交或回滚;其他请求会等待锁释放后再执行查询,从数据库层面保证操作的串行性。

方案二:应用级文件锁(实现请求排队)

如果需要在应用层面控制整个端点的串行处理,可使用文件锁机制,确保同一时间只有一个请求进入业务逻辑。

代码示例:

function addClient($request) {
    // 指定锁文件路径,需确保所有进程有读写权限
    $lockFile = __DIR__ . '/add_client_lock.txt';
    $lockHandle = fopen($lockFile, 'w');
    
    // 阻塞等待锁,直到获取到权限
    if (!flock($lockHandle, LOCK_EX)) {
        echo '{"error":{"text":"当前请求过多,请稍后重试"}}';
        fclose($lockHandle);
        return;
    }

    $client = json_decode($request->getBody());
    $sql = 'select unique column';

    try {
        $db = getConnection();
        $stmt = $db->prepare($sql);
        $stmt->execute();
        $row = $stmt->fetch(PDO::FETCH_ASSOC);

        if(some logic)
        {
            $get_card_query = "insert into another_table (target_column) values (?)";   
            $stmt = $db->prepare($get_card_query);
            $stmt->bindParam(1, $row[0]);
            $stmt->execute();
        }
        $db = null;
    } catch(PDOException $e){
        echo '{"error":{"text":'. $e->getMessage() .'}}';
    } finally {
        // 必须释放锁,避免死锁
        flock($lockHandle, LOCK_UN);
        fclose($lockHandle);
    }
}
  • 核心逻辑:LOCK_EX是排他锁,同一时间只有一个进程能获取;未获取到锁的请求会阻塞等待,直到锁被释放,实现请求排队处理。

方案三:修改INSERT语句避免冲突

如果业务允许不严格串行,仅需避免报错,可直接修改INSERT语句,利用数据库的冲突处理机制:

// 替换原INSERT语句为:
$get_card_query = "INSERT INTO another_table (target_column) VALUES (?) ON DUPLICATE KEY UPDATE target_column = VALUES(target_column)";
  • 逻辑说明:当出现重复插入时,会执行更新操作(可根据业务需求调整为不做任何操作),不会抛出错误,但无法保证请求的串行处理顺序。

内容的提问来源于stack exchange,提问作者ibrahim abdulkhaleq

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 23:43:35