【问题标题】:Select and update a couple of rows in MySQL without collision在 MySQL 中选择并更新几行而不会发生冲突
【发布时间】:2015-11-13 16:41:56
【问题描述】:

请考虑有一个充满记录的存储表。将有许多并发请求从存储表中挑选和拥有一些记录。

我不确定,也不知道如何使用 Transcations 将 select 和 update 结合起来,在没有任何联合的情况下完成我所说的。

例如,那是我的桌子:

+----+------+----------+
| id | name | is_taken |
+----+------+----------+
|  1 | a    |        1 |
|  2 | b    |        0 |
|  3 | c    |        0 |
|  4 | aa   |        1 |
|  5 | bb   |        0 |
|  6 | dd   |        0 |
|  7 | e    |        0 |
|  8 | ff   |        0 |
+----+------+----------+

--

-- first select them
SELECT * FROM `STASH` WHERE `is_taken` = 0 LIMIT 2
-- then update and take them to stop others to taking them
UPDATE `STASH` SET `is_taken` = 1 WHERE `is_taken` = 0

【问题讨论】:

    标签: mysql transactions innodb mariadb


    【解决方案1】:

    如果您将表格用作操作队列并且它们很短:

    START TRANSACTION;
    SELECT ... FOR UPDATE;
    act on them
    DELETE ...; -- assuming you are finished with them.
    COMMIT;
    

    并在每个阶段检查错误。如果遇到死锁或锁等待超时,请重新启动。

    如果操作需要很长时间,则应使用不同的技术。

    所以,请详细说明

    • 表格中通常(和最大)有多少行
    • 您想一次选择多少行
    • “处理”一行需要多长时间
    • 完成后是否可以删除行。

    不同的技术效果更好,具体取决于您的答案。

    【讨论】:

      【解决方案2】:

      如果还没有所有者列,您可能需要考虑将所有者列添加到表中。然后只需运行更新语句,设置所有者并获取该行。每个逻辑事务都应该有唯一的所有者。

      update stash set owner = some_owner, is_taken = 1 where is_taken = 0 limit 2;
      

      这个语句应该在你预期的并发负载下进行测试,看看它是如何执行的。

      然后选择那些行

      select * from stash where owner = some_owner and is_taken = 1;
      

      然后是时候释放了,使用上面选择的id

      update stash set owner = null, is_taken = 0 where id in (...);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-03-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-12
        • 2011-12-03
        • 2016-04-07
        相关资源
        最近更新 更多