【发布时间】:2017-07-01 04:11:57
【问题描述】:
我正在开发一个金融系统,但我遇到了 MySQL 事务的问题。
该系统是一个简单的证券交易所,用户可以在其中买卖虚拟股票。为了保持买卖过程的完整性,我使用交易。 问题是在某些情况下(我不知道它取决于什么)一些事务被回滚(或未提交),但处理下一个查询。
流程如下:
- 用户想以 1000 美元购买股票
- 在订单中有 4 个报价为 250 美元
START TRANSACTION- 对于每个报价:
- 脚本执行更新查询(将美元从一个用户转移到另一个用户并以相反的方式共享)。然后脚本 INSERTs 条目到历史表。
- 用户支付费用(更新余额)。
- 重复 5 和 6 以获得下一个报价。
COMMIT
现在关键部分 - 在某些情况下,从第 5 点开始的更改没有保存,但从第 6 点开始保存(我看到已支付费用,但历史记录中没有交易)。
在此交易期间我没有使用ROLLBACK,并且脚本没有中断(因为在这种情况下不会支付费用)。
如果没有ROLLBACK 查询,事务是否有可能回滚?或者 MySQL 可以只提交几个最新的查询而不是全部?
【问题讨论】:
-
不,事务应该始终是原子的。要么什么都做,要么什么都不做。
-
系统中的第一个漏洞是您在交易前(仅)检查了订单簿,因此它可能已被更改;例如订单 1 可能已被使用,仅留下 3 个未结报价,并且根据您的实际代码,步骤 5 可能不会执行任何操作,但步骤 6 可能仍会收取费用。但这只是一个问题,而且仅在您的概念中。您可能会做错很多其他事情(例如,使用 myisam,使用错误的事务级别,不锁定选择,...),所以这里可能还有其他问题。如果您使用真实货币/价值进行交易,您应该让顾问检查您的代码。
-
我没有在第一篇文章中写过这个(对不起),但我在开始处理之前使用
SELECT FOR UPDATE锁定了行。当我处理单个报价时,我会额外检查,如果报价仍然存在,用户有有效余额等。但是目前它是演示系统。 -
我仍然认为最有可能的怀疑是,即使在检查失败时不执行 5,您也只是执行了 6。并且您的支票 2 必须(也)发生在交易中。但是,如果您不添加实际代码(这对于 stackoverflow 来说可能太多,但您可以尝试 codereview)并且也不添加所有详细信息,例如
for update或其他检查,我们无法告诉您错误行为出现在哪里从。但我们可以向您保证:错误出现在您的代码、数据或设置中。 (工作)事务不可能只是部分执行。 -
我假设
FOR UPDATE是 在 步骤 3 之后?您是否在每个 SQL 之后检查错误,包括COMMIT?
标签: mysql transactions innodb