【发布时间】:2022-11-12 00:23:13
【问题描述】:
我想通过使用 Symfony Lock 组件来防止用户两次发出相同的请求。因为现在用户可以点击链接两次(意外?)并创建重复的实体。我想使用不能防止竞争条件本身的唯一实体约束。
Symfony Lock 组件似乎没有按预期工作。当我在页面的开头创建一个锁并同时打开该页面两次时,两个请求都可以获取锁。当我在标准和隐身浏览器窗口中打开测试页面时,第二个请求没有获得锁。但是我在文档中找不到任何关于此链接到会话的内容。我在一个新项目中创建了一个小测试文件来隔离问题。这是使用 php 7.4 symfony 5.3 和 lock 组件
<?php
namespace App\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Routing\Annotation\Route;
class LockTest extends AbstractController
{
/**
* @Route("/test")
* @Template("lock/test.html.twig")
*/
public function test(LockFactory $factory): array
{
$lock = $factory->createLock("test");
$acquired = $lock->acquire();
dump($lock, $acquired);
sleep(2);
dump($lock->isAcquired());
return ["message" => "testing"];
}
}
【问题讨论】:
-
不熟悉锁组件,但如果您的实体有一个唯一的数据库约束(除了 id),那么只会创建一个。尝试创建另一个只会导致抛出异常。因此,如果您只需要防止重复实体,那么您需要查看如何添加唯一数据库约束。
-
因此,您在一个浏览器中同时打开同一个页面两次,并看到在这两种情况下都获得了锁定,对吧?我认为不是 symfony 锁组件允许您两次获取一个锁。它可能只是普通的php会话锁定:当两个请求同时运行时,第一个获得锁,而第二个被同一个会话锁定。当第一个请求完成时,第二个请求被解锁并成功获取锁。所以首先尝试确保会话被禁用。
-
可以尝试在Symfony's Discussion Board 上发布您的问题。这将提高锁定专家看到它的机会。另外,我假设您正在使用 apache 或 nginx 等实际生产服务器进行测试?开发服务器一次严格来说是一个请求,并且肯定会扭曲这些事情。
-
@Cerad symfony 的唯一实体约束不是数据库约束而是验证器约束。这会在验证时而不是在插入时进行检查,因此可能会发生竞争条件
-
@xtx 是的,我认为它已锁定到会话,php 是否将请求锁定到某个会话?因为在我的用例中,用户已登录,但我想防止用户多次单击并创建重复的实体。
标签: php symfony locking symfony-lock