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

Symfony Lock组件同浏览器发起两次请求时未正常上锁问题咨询

问题根因

你遇到的现象和Symfony Lock组件本身无关,是PHP默认的会话锁机制导致的:

  • 同一浏览器普通窗口共享同一份会话Cookie,PHP默认会给会话加独占锁,同一个会话的多个请求会串行执行:第一个请求持有会话锁直到整个请求处理完成,第二个请求会卡在会话初始化阶段,直到第一个请求结束释放会话锁后才会进入你的控制器逻辑。这就导致你设置的固定Keytest的锁,在第一个请求sleep(2)结束、请求完成自动释放锁之后,第二个请求才执行acquire()方法,自然能成功拿到锁。
  • 隐身窗口属于独立会话,不受同会话锁限制,两个请求会并行进入控制器逻辑,所以第二个请求无法获取锁,符合Lock组件的预期表现。

解决方案

1. 验证Lock组件效果(测试用)

如果要测试同会话下的锁并发效果,可以给路由关闭会话锁:

/**
 * @Route("/test", options={"session_lock"=false})
 * @Template("lock/test.html.twig")
 */
public function test(LockFactory $factory): array
{
    // 原有逻辑不变
}

调整后再在同一浏览器开两个标签访问,就能看到第二个请求拿锁失败的预期结果。

2. 实现防重复提交的正确用法

你当前用全局固定Keytest的方式有问题,会导致所有用户共用同一把锁,一个用户提交后其他人都无法操作,需要按业务维度生成唯一锁Key:

public function submit(LockFactory $factory): array
{
    // 按「用户ID + 业务操作标识」生成唯一锁Key,也可以加入表单CSRF Token、待创建实体的唯一特征值进一步精准控制
    $lockKey = 'create_entity_' . $this->getUser()->getId();
    // 第二个参数为锁自动过期时间,需大于业务最长处理时长
    $lock = $factory->createLock($lockKey, 30);
    
    if (!$lock->acquire()) {
        throw $this->createAccessDeniedException('请勿重复提交请求');
    }
    
    try {
        // 你的业务处理逻辑
    } finally {
        // 处理完成主动释放锁,避免等待自动过期
        $lock->release();
    }
    
    // 表单提交场景建议配合Post/Redirect/Get模式,进一步降低重复提交概率
    return $this->redirectToRoute('xxx');
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 10:24:01