【问题标题】:How to implement atomic transaction in mysql?如何在mysql中实现原子事务?
【发布时间】:2022-01-12 17:55:09
【问题描述】:

我正在开发我的演示项目 - 它是一个简单的银行。

我有一个问题。

我需要在我的帐户中添加一些虚拟货币。

但是我需要“像原子操作一样”,我需要在更新之前查询一些数据。

喜欢:

Query table A // select from table A
Query table B // select from table B
if (A + B > X) 
Add money // insert into table C

问题是,在查询 A 或 B 期间,另一个线程可以开始一些工作。

我应该使用哪种mysql技术?

示例: 快乐的例子

User see A = 1, B = 1 in dashboard
User will send request

SELECT A
SELECT B
INSERT A + B // result is 2

悲惨的例子

User see A = 1, B = 1 in dashboard
User will send request

SELECT A
// SOMEONE CHANGED B RIGHT NOW TO 10 !
SELECT B
INSERT A + B // result is 12

【问题讨论】:

  • 你应该使用TRANSACTIONs
  • 选择无关紧要,您将事务包装在 INSERTS 和 UPDATES 周围,以便它们全部成功运行,或者在错误回滚之前完成的那些,因此数据库看起来没有发生任何事情。您只是在更改表 C
  • 但是有人可以“破坏”选择中的数据。比如,有人可以更改我的数据,例如“关键部分”。
  • 您可以使用插入...选择...或锁定读取(选择...进行更新)。
  • 这就是锁定读取的用途。

标签: mysql atomic


【解决方案1】:

如果我理解正确的话,我过去曾这样做过,但没有使用这样的锁定读取:

假设用户 A 想要将 5 美元从他们的账户转移到用户 B 的账户。安全地执行此操作的伪代码可能如下所示:

  1. 开始交易。
  2. UPDATE Account SET Balance = Balance - 5 WHERE User = 'A' AND Balance >= 5
  3. 如果 #2 返回的受影响行为零,则回滚事务 - 这表示资金不足,否则继续
  4. UPDATE Account SET Balance = Balance + 5 WHERE User = 'B'
  5. 提交事务

我相信这应该消除任何竞争条件的可能性,同时也消除不必要的读取。

【讨论】:

    【解决方案2】:

    仅交易不会满足您的需求。 MySQL 中的普通读取查询不会阻止其他会话更新行。

    在此处了解 MySQL 中的锁定读取:https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html

    为了防止您提到的竞争条件,您需要在单个原子操作中获取 A 和 B 上的锁。您可以通过使用JOINUNION 对两个资源进行锁定读取来做到这一点。

    您还可以锁定整个表,并以原子方式锁定多个表。见https://dev.mysql.com/doc/refman/8.0/en/lock-tables.html

    【讨论】:

    • 嗨,比尔,我的示例是“SERIALIZABLE”事务解决方案吗?
    • SERIALIZABLE 将普通读取转换为锁定读取,就好像您对每个查询都做了SELECT ... LOCK IN SHARE MODE。这将阻止针对锁定行的并发更新,但您仍然需要注意创建一个会锁定多个资源的 SELECT。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多