条令实体管理器和多线程更新数据库


Doctrine entity manager and multiple threads updating database

我目前有一个XHR请求,可以从客户端触发N次。这些请求由服务器处理,每个请求通常在数据库中创建一个新行(全部为条令/xml)。

在持久化()对象之前,我会确保if有一个唯一的文件名(我正在上传资产),并通过重写持久化((),调用我的getUniqueFilename(),然后调用parent::persistent来实现这一点。

当我使用相同的文件名执行多个XHR请求时,我会遇到竞争条件。如果多个线程同时运行并检查数据库中的重复项以生成唯一的文件名,会发生什么情况。

  • 上载文件
  • 检查数据库是否存在文件名
  • 增加文件名(例如:filename_1)

但是,当多个XHR请求发生在多个线程中时,会出现竞争条件,其中多个文件插入到具有相同名称的数据库中(多次生成filename_1)。

我认为解决这个问题的方法要么是

  • mysql触发器
  • 向表中添加文件名的唯一约束,并包装代码中的try/catch

你会怎么做?

添加唯一约束是确保数据一致性的最安全方法。PHP级别的任何东西都可能有一些竞争条件,除非你有其他形式的锁定,否则效率会降低。

您还可以通过使用其他属性(如文件名来自的用户)确保文件名是唯一的,或者保留版本历史记录来避免这个问题,这会使文件名看起来几乎同时有一个新版本。

我建议使用不同的策略:使用mysql auto_increment获取id,将资产保存到数据库中,检索id,然后将其添加到文件名中。所有其他方法都有缺点,必须执行部分回滚、处理重复文件名等。

我还建议不要使用原始文件名来存储对象:您在不同的操作系统上遇到了禁止使用的字符以及字符编码的问题,出于某种原因可能会出现重复(例如,因为数据库对文件系统不敏感的情况敏感)。可能还有其他缺点,比如文件名的最大长度,你现在可能还没有意识到。

我的解决方案只是简单地使用mysql自动增量作为文件名。如果你仔细想想,这是有道理的。自动增量用作唯一标识符。如果你确保只将一个表中的故事对象放入一个文件夹,那么识别不同的资产、文件名等就没有问题。

如果你坚持按照自己的方式,你可以让文件名在数据库中是唯一的,然后按照你的建议在刷新失败时重新启动。