这是mysql线程安全的吗?

时间:2020-03-30 09:27:37

标签: mysql concurrency transactions

我有一个包含以下列的表格:id(int), wallet_id (int), amount (int), recharge_date (timestamp), status (int)status表示待定(0),成功(1)或失败(2)。我需要确保在充值之前,本月充值的总金额不超过10,000。我还需要涵盖具有2个或更多同时充电请求的场景。

我认为以下步骤可以帮助避免出现竞争状况:

  1. 将状态为0(待处理)的表插入一个wallet_id,说“ 1234”
  2. 从表中选择sum(amount),其中wallet_id = 1234 AND month(recharge_date)=当前月份和(0,1)中的状态
  3. 如果总和超过10,000,则将状态更新为2(失败)并返回。
  4. 执行一些应用程序级别的操作,然后将状态更新为1(成功)或2(失败)

这些步骤是否确保线程安全?另外,在此用例中,还有其他任何更简单的方法来确保线程安全吗?

编辑: 解释实际流程以更清楚:

  1. 服务器收到为某个wallet_id(例如99)添加500的请求。
  2. 以待处理状态插入新订单:INSERT INTO order VALUES(wallet_id = 99,金额= 500,状态=待处理)
  3. 需要确保您一个月内最多可​​以充值10,000次。因此,选择SUM(amount)WHERE wallet_id = 99 AND month = current_month AND status IN(待审核,成功)
  4. 如果步骤3中的总和> = 10,000,则将步骤2中创建的订单状态更新为失败。返回
  5. 如果总和<10,000,则执行其他操作,请返回并将步骤2中创建的顺序更新为成功或失败。

如果对此流程同时收到多个请求,则会引起混乱。

1 个答案:

答案 0 :(得分:1)

并发性很好。为此Database transactions

您可以通过这样的交易来做到这一点。 (未调试)

BEGIN TRANSACTION;

SELECT SUM(amount) INTO @sum
  FROM mytable
 WHERE status IN (0,1)
   AND recharge_date >= LAST_DAY(CURDATE()) + INTERVAL 1 DAY - INTERVAL 1 MONTH
   AND recharge_date < LAST_DAY(CURDATE()) + INTERVAL 1 DAY 
   AND wallet_id = (((whatever))
   FOR update;

UPDATE mytable SET status=2
 WHERE status IN (0,1)
   AND recharge_date >= LAST_DAY(CURDATE()) + INTERVAL 1 DAY - INTERVAL 1 MONTH
   AND recharge_date < LAST_DAY(CURDATE()) + INTERVAL 1 DAY 
   AND wallet_id = (((whatever))
   AND @sum > 1000;

/* then do your application logic, and come back and do */

UPDATE mytable SET status=(((whatever)))
 WHERE status IN (0,1)
   AND recharge_date >= LAST_DAY(CURDATE()) + INTERVAL 1 DAY - INTERVAL 1 MONTH
   AND recharge_date < LAST_DAY(CURDATE()) + INTERVAL 1 DAY 
   AND wallet_id = (((whatever))
   AND @sum > 1000;

/* finally, commit your transaction. */
COMMIT;

请注意SELECT...FOR UPDATE和两个UPDATE语句如何都具有相同的WHERE语句。这很重要,因为您必须避免更新未选择进行更新的行。完成后,COMMIT进行交易。如果您决定不想在BEGIN TRANSACTION之后的任何时间继续进行交易,则可以ROLLBACK进行交易,事情恢复到开始之前的状态。

此模式

   AND recharge_date >= LAST_DAY(CURDATE()) + INTERVAL 1 DAY - INTERVAL 1 MONTH
   AND recharge_date < LAST_DAY(CURDATE()) + INTERVAL 1 DAY 

是选择当前日历月中日期的最佳方法。它允许使用列上的索引来搜索相关记录,而MONTH(recharge_date) = MONTH(CURDATE())则不然。

我对一件事有些困惑。您说您需要做一个SUM,这表明表中的多条记录受预期的status更改的影响。那真的是您想要的吗?

相关问题