简体   繁体   English

如何避免MySQL InnoDB中的竞争条件?

[英]How to avoid race condition in MySQL InnoDB?

We're using MySQL InnoDB. 我们正在使用MySQL InnoDB。 The system support multiple request that can happen simultaneously. 系统支持可以同时发生的多个请求。 Here is a simplified example of what we're trying to achieve. 这是我们要实现的目标的简化示例。 Let's assume we have a table that holds entities that represent light bulb. 假设我们有一个表,其中包含代表灯泡的实体。 These light bulbs can be turned on (activated) by users. 用户可以打开(激活)这些灯泡。 Users can add light bulbs to the table, which initially are deactivated, and only 10 of them can be marked as activated. 用户可以将灯泡添加到表中,该灯泡最初是停用的,并且只能将其中的10个标记为已激活。 So we have a limit of 10. Since the system supports concurrency, there is a risk of race condition based on the following example: 因此我们的限制为10。由于系统支持并发,因此基于以下示例,存在竞争状态的风险:

SESSION 1: 第一场:

1: Get the number of active bulb 1:获取活动灯泡的数量

2: Check the number of activated bulbs 2:检查已激活灯泡的数量

3: If limit not reached yet, activate the bulb and commit. 3:如果尚未达到极限,请启动灯泡并提交。

4: Otherwise rollback. 4:否则回滚。

The issue here is that during step 2 and 4 another session could enter and could end up exceeding the limit. 这里的问题是,在第2步和第4步期间,另一个会话可能会进入并可能超出限制。

This is a sql representation of what we are doing currently: 这是我们当前正在执行的sql表示:

  1. SELECT count(id) AS total FROM tbl WHERE is_active = 1; SELECT count(id)AS总计from tbl WHERE is_active = 1;
  2. if(total < 10) { if(total <10){
  3. activate another bulb; 启动另一个灯泡; } else { }其他{
  4. rollback; 回滚 } }

What do you recommend as a solution for this scenario? 您对此方案有什么建议? We were considering "select for update" but that, if I'm not mistaken, locks selected rows and users can add bulbs to the table while selected rows are under lock. 我们正在考虑“选择更新”,但是,如果我没有记错的话,它会锁定选定的行,并且用户可以在选定的行处于锁定状态时将灯泡添加到表中。

Thank you. 谢谢。

One idea is to keep a separate locking table where you manage this limit requirement and make only atomic updates to the count of active bulbs like: 一种想法是保留一个单独的锁定表,在该表中管理此限制要求,并仅对活动灯泡的数量进行原子更新,例如:

update active_bulb_count
    set active_count = active_count + 1
    where active_count < limit
      and <any other conditions needed>;

If no rows updated you know the limit has been met, so you wouldn't set the bulb active. 如果没有更新任何行,您将知道已达到限制,因此您不会将灯泡设置为活动状态。

You should probably still consider your transaction setup for the session that performs this action. 您可能仍应考虑执行此操作的会话的事务设置。 See more details on atomic update and transactions MySQL Atomic UPDATE in InnoDB vs MyISAM 在InnoDB和MyISAM中查看有关原子更新和事务的更多详细信息MySQL Atomic UPDATE

BEGIN;   -- start a "transaction"
do the 4 steps
COMMIT;  -- or ROLLBACK

Note: Any SELECTs that may lead to an UPDATE need to say FOR UPDATE . 注意:任何可能导致UPDATE SELECTs都必须说FOR UPDATE

And/or, look into how to do more work in an UPDATE (see churd's answer). 和/或,研究如何在UPDATE做更多的工作(请参阅churd的答案)。 Or INSERT ... ON DUPLICATE KEY UPDATE ... INSERT ... ON DUPLICATE KEY UPDATE ...

Keep in mind that INSERT and UPDATE can report how many rows were affected. 请记住, INSERTUPDATE可以报​​告受影响的行数。 This can be used to "assume the task will succeed", then check if it did and take evasive action if it failed. 这可以用来“假定任务将成功”,然后检查任务是否成功,如果失败则采取规避措施。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM