我有一个包含以下列的表格:id(int), wallet_id (int), amount (int), recharge_date (timestamp), status (int)
。 status
表示待定(0),成功(1)或失败(2)。我需要确保在充值之前,本月充值的总金额不超过10,000。我还需要涵盖具有2个或更多同时充电请求的场景。
我认为以下步骤可以帮助避免出现竞争状况:
这些步骤是否确保线程安全?另外,在此用例中,还有其他任何更简单的方法来确保线程安全吗?
编辑: 解释实际流程以更清楚:
如果对此流程同时收到多个请求,则会引起混乱。
答案 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
更改的影响。那真的是您想要的吗?