【问题标题】:Is MariaDB (MySQL) UNION atomic?MariaDB (MySQL) UNION 是原子的吗?
【发布时间】:2020-10-21 00:03:07
【问题描述】:

假设我有两个 InnoDB 表 - TableATableBTableB 中只有一条记录,TableA 为空。

我也有两个并行的进程。

Process1TableATableB 中寻找一行。它执行两条 SQL 语句 - select * from TableA,然后是 select * from TableB

Process2 想要将记录从TableB 移动到TableA。它启动一个事务,然后执行查询delete from TableBinsert into TableA

不幸的是,这里有一个竞争条件。如果Process2 移动而Process1 在两个select 语句之间的某个位置停止,那么Process1 将永远看不到该行。

解决此问题的一种方法是交换select 语句并首先从TableB 中选择。连同事务和至少READ COMMITED 隔离级别,应该足以检测到至少一张表中的记录。

但是我想知道select * from TableA union all select * from TableB 是否也可以解决问题?我认为它会减少所涉及的部分,并使其不太可能因未来的代码更改而中断(无需担心语句顺序)。但它是否消除了竞争条件?

如果重要,请使用最新的 MariaDB 版本。

【问题讨论】:

    标签: mysql concurrency transactions mariadb race-condition


    【解决方案1】:

    测试每个:

    A 计划:您建议的 UNION。

    B 计划:将SELECTs 包装在一个事务中,并在每个事务上使用FOR UPDATE

    Plan C:包装在事务中并使用隔离模式SERIALIZABLE。我更喜欢这个,因为它表明你真的不能让两个线程同时接触这些表。

    警告:我不知道哪些会/不会起作用。

    【讨论】:

    • 嗯...工会有点难以测试,因为设置比赛条件很大程度上取决于运气和我不知道的因素。我认为for update(加上一个事务)会起作用(因为它会锁定),但在这种情况下,要么我冒死锁的风险,要么选择的顺序再次变得重要。而SERIALIZABLE 简化为for update 的情况。
    • 您应该始终针对可能出现的错误进行编码,包括死锁。
    • 无交易 - 无死锁! ?虽然你当然是对的。然而,我试图减少锁定,坚持简单的自动提交语句并改用乐观锁定。碰撞应该很少见。虽然在那种情况下可能没关系,我可以使用带有常规锁的常规事务?我会...必须考虑一下。
    • @Vilx- - LOCK TABLE 不应与 InnoDB 一起使用。自动提交包括锁。
    • 不,不,你误会我了。我不是要锁定整张桌子!那将是一场灾难。我的意思是将记录锁定在TableB。这两个进程都以select ... from TableB for update 开头,然后一次只有一个进程可以工作。一个非常简单的解决方案,实际上也简化了许多其他事情......除了有时记录不存在,然后创建它是过程的工作。那会发生什么?如果我能解决那部分,我很好。
    猜你喜欢
    • 1970-01-01
    • 2018-12-08
    • 1970-01-01
    • 2011-10-14
    • 2023-01-22
    • 1970-01-01
    • 1970-01-01
    • 2011-03-03
    • 2010-12-11
    相关资源
    最近更新 更多