Является ли ОБЪЕДИНЕНИЕ MariaDB (MySQL) атомарным?

#mysql #concurrency #transactions #mariadb #race-condition

#mysql #параллелизм #транзакции #mariadb #условие гонки

Вопрос:

Допустим, у меня есть две таблицы InnoDB — TableA и TableB . В нем есть одна запись, TableB и TableA она пуста.

У меня также есть два параллельных процесса.

Process1 ищет строку в любом TableA или TableB . Он выполняет два оператора SQL — select * from TableA и затем select * from TableB .

Process2 хочет переместить запись из TableB в TableA . Он запускает транзакцию, а затем выполняет запросы delete from TableB и insert into TableA .

К сожалению, здесь есть условие гонки. Если Process2 делает свой ход, пока Process1 он останавливается где-то между двумя select операторами, то Process1 никогда не увидит строку.

Одним из способов решения этой проблемы было бы поменять select местами операторы и сначала выбрать из TableB . Вместе с транзакцией и, по крайней мере READ COMMITED , уровнем изоляции, которого должно быть достаточно для обнаружения записи хотя бы в одной таблице.

Однако мне было интересно, будет ли a select * from TableA union all select * from TableB также делать трюк? Я думаю, что это уменьшило бы вовлеченные части и уменьшило бы вероятность разрыва при будущих изменениях кода (не нужно беспокоиться о порядке операторов). Но устраняет ли это условие гонки?

Если это имеет значение, предположите последнюю версию MariaDB.

Ответ №1:

Протестируйте каждый из них:

План А: ОБЪЕДИНЕНИЕ, которое вы предлагаете.

План Б: оберните SELECTs в транзакцию и используйте FOR UPDATE для каждого.

План C: завершите транзакцию и используйте режим изоляции SERIALIZABLE . Я предпочитаю это, потому что это указывает на то, что у вас действительно не может быть двух потоков, одновременно затрагивающих эти таблицы.

Предостережение: я не знаю, какие из них будут / не будут работать.

Комментарии:

1. Хм… Объединение довольно сложно протестировать, потому что настройка условия гонки будет во многом зависеть от удачи и факторов, которые я действительно не знаю. for update Я думаю, что (плюс транзакция) будет работать (поскольку она будет заблокирована), но в этом случае либо я рискую зайти в тупик, либо порядок выбора снова становится важным. И SERIALIZABLE сводится к for update делу.

2. Вы всегда должны кодировать возможность ошибок, включая взаимоблокировки.

3. Нет транзакций — нет взаимоблокировок! 😁 Хотя вы, конечно, правы. Однако я пытался уменьшить блокировку, придерживаясь простых операторов автоматической фиксации и используя вместо этого оптимистичную блокировку. Столкновения должны быть редкими. Хотя в этом случае, возможно, это не должно иметь значения, и я могу просто использовать обычные транзакции с обычными блокировками? Я буду… нужно подумать об этом.

4. @Vilx- — LOCK TABLE не следует использовать с InnoDB. Автоматическая фиксация включает блокировки.

5. Нет, нет, вы меня неправильно поняли. Я не имею в виду блокировать всю таблицу! Это было бы катастрофой. Я имею в виду блокировку записи TableB . Оба процесса будут начинаться с select ... from TableB for update , а затем одновременно будет работать только один из них. Очень простое решение и действительно упрощает многие другие вещи … за исключением того, что иногда записи там нет, и тогда процесс создает ее. Что происходит тогда? Если я смогу решить эту часть, я в порядке.