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

发布于 2024-10-14 14:34:45 字数 438 浏览 3 评论 0原文

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

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

可能发生的情况的一个示例是:

  • 我们正在等待 20 个人将商品添加到他们的愿望清单中,而我们有 19 个。Bob
  • 和 Sally 访问该网站并单击“添加到愿望清单”按钮
  • 服务器收到 Bob 的请求,看到现已满足 20 个请求,并收取费用。
  • 同时服务器收到 Sally 的请求,并且由于同时收到 Bob 的订单,因此在 db 中仍然看到 19 个请求,开始处理付款。因此,付款被收取两次。

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

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

On my website, people can add an item to their wishlist. When X number of people have added it to their list, then all those peoples' credit cards are charged.

The problem I'm facing is how to ensure that if two customers add it to their wishlist at the same time, then the payment processing code won't run twice. Any ideas?

An example of what can happen is:

  • We are waiting for 20 people to add the item to their wishlist, and we have 19.
  • Bob and Sally visit the site and click the 'add to wishlist' button
  • The server receives Bob's request, sees that 20 requests are now met, and charges the payments.
  • At the same time the server receives Sally's request, and still seeing 19 requests in db since Bob's order was simultaneously received, begins to process the payments. Hence, the payments are charged twice.

Any ideas on how to avoid this?

I am using a MySQL database and PHP for the programing.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

旧伤慢歌 2024-10-21 14:34:45

这就是交易设计的目的。卡的收费和 wislist 计数的重置必须在同一事务中进行,以便它们作为原子单元发生。此外,为了避免您所描述的问题,您必须将事务隔离级别至少设置为“已提交读”“可重复读”。

附加信息:

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

它的工作原理如下:当应用程序对愿望清单表进行选择以检索事务内的计数时,数据库会在与此查询关联的表上放置读锁。如果在前一个事务挂起期间打开的另一个事务尝试读取这些相同的表,则它必须等待,直到前一个事务具有 COMMIT 或 ROLLBACK。如果前一个事务提交,那么下一个事务将看到计数 0 和所有其他修改。否则,如果应用程序出于任何原因执行 ROLLBACK,则任何数据都不会更改,并且下一个事务会看到第一个事务之前存在的数据。

This is the type of thing for which transactions are designed. The charging of the cards and the reseting of the wislist count must be in the same transaction so that they occur as an atomic unit. Furthermore, to avoid the problem you are describing, you must set the transaction isolation level to at least "Read Committed" "Repeatable Read".

Additional information:

Here's how to do it: 1. The app opens a transaction on the database. 2. The app does a select on the wishlish tables to retrieve the count. 3. If the count is >= n, the app does another select on the wishlist and related tables to retrive the pending wishlist orders, users, card info, etc. 4. Depending on the business rules regarding card transactions, the app then deletes the pending orders, or whatever to reset the wishlist count back to zero. 5. The app then closes the transaction.

Here's why it works: when the app does a select on the wishlist tables to retrieve the count inside a transaction, the db places a read lock on the tables associated with this query. If another transaction that opened during the pendency of the prior transaction tries to read those same tables, it must wait until the prior transaction has either a COMMIT or a ROLLBACK. If the prior transaction COMMITS, then the next transaction will see a count of 0 and all the other modifications. Otherwise, if the app executes a ROLLBACK for any reason, none of the data changes and the next transaction sees the data as it existed prior to the first transaction.

妞丶爷亲个 2024-10-21 14:34:45

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

您的进程是幂等的,这一点很重要。在这种情况下,这意味着如果您多次运行我们的收费服务,则已收费的订单不会被收取两次费用。

我通过在下订单时将 OrderStatus 设置为“NotProcessed”来实现此目的。
一旦服务运行并对订单收费,OrderStatus 就会更改为“PaymentPending”。
仅当订单状态为“未处理”时,我才对订单收费。

伪代码:

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

I am doing a similar site at the moment. Seems to be popular...

It is important that your processes are idempotent. In this context, this means that if you run our charging service multiple times, the orders which have already been charged are not charged twice.

I accomplish this by setting the OrderStatus to 'NotProcessed' when the order is placed.
Once the service runs and charges for an order the OrderStatus changes to 'PaymentPending'.
I charge for the order only if the OrderStatus is 'NotProcessed'.

PSEUDO CODE:

void ProcessPendingOrders()
{
   var orders = getAllOrders();
   foreach(Order order in orders)
   {
    if (order.OrderStatus == NotProcessed)
       ChargeOrder(order)
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文