如何避免繁忙站点上的数据双重处理?

时间:2011-01-26 20:42:03

标签: database scalability

在我的网站上,人们可以将项目添加到他们的心愿单中。当X个人将其添加到他们的列表中时,所有这些人的信用卡都被收费。

我面临的问题是如何确保如果两个客户同时将其添加到他们的心愿单,那么支付处理代码将不会运行两次。有什么想法吗?

可能发生的一个例子是:

  • 我们正在等待20个人将该项目添加到他们的心愿单中,我们有19个。
  • Bob和Sally访问该网站并点击“添加到心愿单”按钮
  • 服务器接收Bob的请求,看到现在满足了20个请求,并收取付款。
  • 同时服务器收到Sally的请求,并且自从同时收到Bob的订单后仍然在db中看到19个请求,开始处理付款。因此,付款将收取两次费用。

关于如何避免这种情况的任何想法?

我正在使用MySQL数据库和PHP进行编程。

2 个答案:

答案 0 :(得分:1)

这是设计交易的类型。卡的充电和wislist计数的重置必须在同一事务中,以便它们作为原子单元出现。此外,为了避免您描述的问题,您必须将事务隔离级别设置为至少“Read Committed”“Repeatable Read”。

其他信息:

以下是如何操作:1。应用程序在数据库上打开一个事务。 2.应用程序对愿望表进行选择以检索计数。 3.如果计数是> = n,则应用程序会在心愿单和相关表上执行另一个选择,以检索待处理的愿望清单,用户,卡信息等.4。根据有关卡交易的业务规则,应用程序然后删除挂单,或者将心愿单计数重置为零的任何内容。 5.然后应用程序关闭交易。

以下是它的工作原理:当应用程序对wishlist表进行选择以检索事务内的计数时,db会对与此查询关联的表进行读锁定。如果在先前事务的未决期间打开的另一个事务尝试读取那些相同的表,则它必须等到前一个事务具有COMMIT或ROLLBACK。如果先前的事务COMMITS,则下一个事务将看到0的计数和所有其他修改。否则,如果应用程序因任何原因执行ROLLBACK,则没有数据发生更改,下一个事务会看到第一个事务之前存在的数据。

答案 1 :(得分:0)

我现在正在做一个类似的网站。似乎很受欢迎......

您的流程必须是幂等的。在这种情况下,这意味着如果您多次运行我们的充电服务,则已经收费的订单不会收取两次费用。

我通过在下订单时将OrderStatus设置为'NotProcessed'来实现此目的。 一旦服务运行并对订单收费,OrderStatus就会更改为“PaymentPending”。 只有在OrderStatus为'NotProcessed'时才收取订单。

PSEUDO CODE:

void ProcessPendingOrders()
{
   var orders = getAllOrders();
   foreach(Order order in orders)
   {
    if (order.OrderStatus == NotProcessed)
       ChargeOrder(order)
    }
}