【问题标题】:Doctrine entity manager and multiple threads updating database学说实体管理器和多线程更新数据库
【发布时间】:2012-02-27 21:55:12
【问题描述】:

我目前有一个可以从客户端触发 N 次的 XHR 请求。此请求由服务器处理,每个请求通常在数据库中创建一个新行(所有学说/xml)。

在我persist() 对象之前,我确定是否有一个唯一的文件名(我正在上传资产),我通过覆盖persist()、调用我的getUniqueFilename() 然后调用parent::persist 来做到这一点。

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

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

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

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

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

你会怎么做?

【问题讨论】:

  • 如果文件名需要唯一,我会添加一个约束。让数据层解决这个问题。但无论如何,如果 getUniqueFilename() 做得如此“糟糕”,你为什么还要拥有它呢?
  • 好点 - 最初我们从未测试/考虑过用户在同一请求中上传具有相同文件名的资产(或可能发生的竞争条件)。在测试这个错误时,我正在尝试确定解决它的最佳方法。

标签: php concurrency doctrine symfony


【解决方案1】:

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

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

【讨论】:

  • 是的,我认为唯一约束是一个很好的解决方案。谢谢。
  • 所以我开始实现这个并意识到当它抛出异常时,学说实体管理器“关闭”。所以包装在 try/catch 中并再次尝试 persist() 不起作用:doctrine-project.org/jira/browse/DDC-1037 - 我现在回到绘图板。
  • 如果唯一性约束失败,简单的重试真的应该起作用吗?您是否考虑过构建自己的工作单元?
  • 不,我没有。我对 Symfony2 UoW 不是很熟悉——不过,我会调查一下。目前,我们已提出此问题以解决更紧迫的问题,因此我不会将任何答案标记为已接受。当我重新访问时,我将更新我的选择。感谢大家的意见。
【解决方案2】:

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

我还建议不要使用原始文件名来存储对象:您在不同的操作系统上遇到了禁用字符以及字符编码的问题,可能由于某种原因而重复(例如,因为数据库在文件所在的位置区分大小写)系统不是)。可能还有其他缺点,例如最大文件名长度等,您现在可能不知道。

我的解决方案只是使用 mysql 自动增量作为文件名。如果你仔细想想,这是有道理的。自动增量用作唯一标识符。如果您确保仅将一张表中的对象存储到一个文件夹中,则在识别不同的资产、文件名等方面不会有任何问题。

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

【讨论】:

  • 有趣,您的第一段也是一个很好的解决方案。在我实施任何事情之前,我会考虑一下。谢谢嘘。
  • 是的,你应该玩一下,看看这是否适合你。我在文件上传和上述问题方面遇到了很多问题,所以现在我将始终使用我生成的某种 id 作为文件名,并且永远不会使用原始文件名。如果您需要 url 的文件名左右,您总是可以使用某种控制器来查找文件系统上的名称,然后加载正确的资产。大多数问题都可以在解决使用原始文件名带来的小缺陷时得到解决,特别是当它们突然出现时。
  • 我目前有各种各样的代码可以使用文件名/文件路径,所以我有点符合现有的内部 API。在重新阅读您的答案几次并考虑之后,我不确定它是否会在这种情况下起作用 - 尽管这是一个好主意,并且在其他情况下可能会很好用。我可能会将文件名字段设置为约束并在代码中失败...
猜你喜欢
  • 2016-01-02
  • 1970-01-01
  • 2013-05-03
  • 2012-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-16
相关资源
最近更新 更多