PHP一次多个请求正在创建不正确的数据库条目


PHP multiple requests at once are creating incorrect database entries

我在这里运行的是一个图形文件管理器,类似于OneDrive或OpenCloud之类的东西。文件、文件夹、帐户和主服务器设置都作为JSON编码的对象存储在数据库中(是的,我确实去掉了支持JSON的列)。问题是,如果多个请求同时使用同一个对象,它通常会保存不正确的数据,因为这些请求显然无法相互传递更改。

例如,当某人开始下载时,它加载该文件所有者的帐户对象,增加其带宽计数器,然后在下载结束时将其编码/保存回DB。但假设我一次下载三次同一文件,他们都会加载同一个帐户对象,根据自己的意愿更改数据,并保存回自己的数据,而不考虑其他重叠的数据。在这种情况下,3次下载将显示为1。

除了下载量和带宽被取消计数之外,我还遇到了一个问题,我试图创建一个维护函数来加载服务器对象,但可能在几分钟内不会将其保存回来——当下载发生并一直操纵服务器对象时,这显然不起作用,因为当维护功能完成时,所有这些都将被旧数据覆盖。

基本上这是一个线程问题。我研究过PHP APC,希望能让对象在线程之间全局持久化,但这并不奏效,因为它只是为每个请求序列化/反序列化数据,而不是让每个请求都指向内存中的对象。

如果不完全设计一个完全不同的新系统,我完全不知道如何解决这个问题。。。。这太糟糕了。

任何关于我该怎么做的想法都会很棒。

谢谢!

这不是线程问题。您的数据库既不符合构建数据库的两种标准,甚至包括第一种正常形式:每个单元格必须只包含一个值。当您在DB中存储JSON数据时,您不能编写SQL请求来使该事务成为原子事务。所以,是的,您需要将代码放入垃圾桶。

如果您真的需要让代码正常工作,您可以使用一些互斥来同步运行的PHP脚本。PHP中最常见的实现是文件互斥。

您可以尝试使用flock,我想在从DB获取JSON之前,您已经有了用户id。

$lockfile = "/tmp/userlocks/$userid.txt";
$fp = fopen($lockfile, "w+");
if (flock($fp, LOCK_EX)) {
  //Do your JSON update
  flock($fp, LOCK_UN); //unlock
}else{
   // lock exist 
}

你需要弄清楚的是,当有锁时该怎么办,也许等待0.5秒,然后再次尝试获得锁,或者发送一条消息"只允许同时下载一次"或。。。。