多个应用程序访问相同的数据


Multiple applications accessing the same data

所以我的团队正在用PHP开发一个API。我主要关心的是两个人打电话来更新同一行会发生什么。

因此,如果一个API调用先读取,然后处理信息,然后写入,如果另一个API调用对同一行数据做同样的事情,会发生什么。我们使用的是Postgres或Mysql。

User has 100 dollars.
API Call 1 to ADD 20 1 reads 100.
API Call 2 to Subtract 20 reads 100.
API Call 1 writes 120;
API Call 2 write 80;( instead of 100);

我知道有一个涉及锁定表或行的解决方案,这能解决我的问题吗?

我需要一个解决方案,其中API调用2不会失败,而是等待或重试。

[编辑]

我应该更详细地说明我们正在做什么。这是一个浏览器mmo游戏,其中它有两个部分。一个PHP REST API和Java服务器。

浏览器使AJAX GET API调用例如:构建工厂4万美元PHP API检查是否有足够的资金,并返回JSON。所以,玩家支付4万美元。

我们的服务器tick使用boneCP同时调用数据库以更新Funds等值。

因此,从我前面的例子来看,CALL1将是我们的PHP API,CALL2将是服务器记号。

您需要了解事务、事务隔离和显式行级锁定:

select ... for update

在你的情况下,也要考虑使用表达式。如果你发布这样的东西,你的生活会简单得多:

update account set amount = amount - 20 where id = ?

您的API设计糟糕,需要修复。代替:

  1. 用户有100美元
  2. API对ADD 20 1的调用1读取100
  3. API调用2以减去20读取100
  4. API调用1写入120
  5. API调用2写入80;(而不是100)

相反,您应该有一个类似于的流程

  1. 用户有100美元
  2. API调用1以"将20添加到帐户1",因此帐户1从100更改为120并返回新值120
  3. API调用2以"从帐户1减去20",因此帐户1从120变为100并返回新值100

类似地,如果您在两个帐户之间进行转账,则总是使用执行转账的API调用,而不是执行加法,然后执行单独的减法,反之亦然。

换句话说,您需要重新设计您的API,以便在每个API调用的开始和结束时,您的数据库状态保持一致。为了确保使用多个SQL语句的API调用在中途中止时保持一致,您必须将API调用的工作打包到事务中,如果不使用SERIALIZABLE隔离,如果要在事务中执行read-modify-write,请执行适当的SELECT ... FOR UPDATE命令。

您需要避免客户端应用程序的读取-修改-写入周期。

在读-修改-写不可避免的情况下,因此两个或多个API调用必须保持一致,您应该使用乐观并发控制来防止更新冲突。在这种情况下,您的场景将显示如下:

  1. 用户有100美元
  2. API调用1读取帐户1,获得值100和行版本1
  3. API调用2读取帐户1,获得值100和行版本1
  4. API调用1将20添加到提取的值100,发送新值120和行版本1。成功,因为发送的行版本等于数据库中的行版本
  5. API调用2从提取的值100中减去20,发送新值80和新行版本1失败并返回错误,因为数据库rowversion比发送的rowversion新,所以在我们提取该行后,其他人已经修改了该行。第二个API调用程序必须再次提取该行并重试