Symfony Lock组件同浏览器发起两次请求时未正常上锁问题咨询
问题根因
你遇到的现象和Symfony Lock组件本身无关,是PHP默认的会话锁机制导致的:
- 同一浏览器普通窗口共享同一份会话Cookie,PHP默认会给会话加独占锁,同一个会话的多个请求会串行执行:第一个请求持有会话锁直到整个请求处理完成,第二个请求会卡在会话初始化阶段,直到第一个请求结束释放会话锁后才会进入你的控制器逻辑。这就导致你设置的固定Key
test的锁,在第一个请求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
相关产品推荐
相关产品推荐

