В реальных приложениях доступ к системе базы данных имеет не один пользователь. Когда несколько пользователей получают доступ к одним и тем же данным, возникает проблема параллелизма.

В этой статье я кратко расскажу о некоторых распространенных проблемах параллелизма, которые я недавно узнал в MySQL (СУБД) с использованием механизма хранения InnoDB.

Общие проблемы параллелизма перечислены ниже:

Грязное чтение, неповторяющееся чтение, фантомное чтение, потерянные обновления

Прежде чем углубиться в эти вопросы, я хотел бы представить базовую концепцию состояния гонки. Так как эти проблемы часто называют условиями гонки.

Состояние гонки возникает, когда два или более потока могут получить доступ к общим данным и пытаются изменить их одновременно.

Грязное чтение:

Грязное чтение происходит, когда транзакция считывает данные, которые еще не зафиксированы.

Пример:
Предположим, у вас есть две транзакции A и B. В A вы обновляете баллы клиента с 0 до 10 (еще не совершено). Между тем, в B вы читаете (ВЫБЕРИТЕ) баллы этого конкретного клиента и получаете 10 баллов. Однако что, если транзакция A завершится откатом (данные точек откатываются с 10 до 0)? В этом случае транзакция B имела грязное чтение для этого конкретного клиента. Так как в базе нет таких данных, показывающих, что конкретный покупатель имеет 10 баллов.

В MySQL мы можем применить уровень изоляции транзакции Read Committed, чтобы решить эту проблему. После этого транзакция B может читать только те данные, которые зафиксированы в базе данных.

Неповторяющиеся чтения:

Считывание разных значений данных в одной транзакции.

Пример:
Предположим, у вас есть две транзакции A и B. В A у вас есть утверждения о двойном чтении одних и тех же данных (точек). После первого чтения (SELECT) в A данные (точки) изменяются транзакцией B. В этом случае второе чтение данных в A будет иметь другое значение по сравнению с первым чтением. Это называется неповторяющимся чтением.

В MySQL, если этот сценарий вам не подходит, вы можете применить уровень изоляции транзакции «Повторяющееся чтение», чтобы решить эту проблему. Транзакция A создаст моментальный снимок данных при первом чтении и будет использовать его при последующем чтении этих данных.

Призрачное чтение:

Пример:
Предположим, у вас есть две транзакции A и B. Транзакция A считывает данные клиентов, которые набрали ›10 баллов, и выдает квалифицированным клиентам купоны. Однако после того, как A выполнила чтение клиентов, транзакция B выполняет обновление точек некоторых клиентов. В этом случае некоторые квалифицированные клиенты, обновленные с помощью B, могут не получить купоны. Эта проблема называется фантомным чтением, поскольку транзакция A считывает некоторые фантомные данные.

Решить эту проблему в MySQL можно тремя способами. Первый способ заключается в том, что вы можете снова выполнить транзакцию A в более позднее время, чтобы включить других квалифицированных клиентов. Во-вторых, вы можете использовать предложение (SELECT… FOR UPDATE) для каждой транзакции, и MySQL установит исключительную блокировку на строки, которые в данный момент читаются. Третий способ заключается в том, что вы можете применить уровень изоляции транзакции «Сериализуемый».

В случае применения Serializable, когда транзакция A выполняет чтение (еще не зафиксировано) данных (клиентов), она будет знать об изменениях, которые в настоящее время вносятся другими транзакциями в данные (клиенты), и он будет ждать их завершения. Однако применение Serializable может снизить производительность и масштабируемость базы данных, поскольку для этого требуются дополнительные ресурсы от сервера базы данных с точки зрения памяти и ЦП. Кроме того, вам может потребоваться приложить дополнительные усилия для повторной выдачи неудавшихся транзакций из-за тупиковых ситуаций.

Утраченные обновления:

Этот вопрос немного сложный. Во-первых, нам нужно определить, что такое потерянные обновления.

Есть два общих определения:

Первый считает, что потерянное обновление имело место, когда данные, которые были обновлены одной транзакцией, перезаписываются другой транзакцией до того, как первая транзакция будет либо зафиксирована, либо откатана. Этот тип потерянного обновления не может произойти в SQL Server 2005, потому что он не разрешен ни на каком уровне изоляции транзакции.

(Насколько я понимаю, в MySQL при любом уровне изоляции транзакции, если одна транзакция пытается изменить строку или несколько строк, MySQL блокирует эти строки, и эта блокировка не позволит другим транзакциям изменять эти строки до тех пор, пока первая транзакция не будет сделано)

Другая интерпретация утерянного обновления показана на следующем рисунке.

Модификация данных (количество), выполненная транзакцией A, перезаписывается транзакцией B. Однако на самом деле это неплохая вещь в базе данных, мы просто не знаем, что данные (количество) изменяются после того, как мы прочитали данные в транзакция Б.

Чтобы решить второе определение проблем с потерянными обновлениями в MySQL, мы можем использовать атомарные операции (UPDATE inventory SET количество = количество - 4). При использовании этой операции количество данных (элемент A) в конечном итоге будет равно 5. Или мы можем решить эту проблему, применив уровень изоляции транзакции «Сериализуемый» (может потребоваться повторно выполнить неудачные транзакции из-за взаимоблокировок).

p.s. При использовании Повторяемого чтения в MySQL по-прежнему будут происходить потерянные обновления.

Заключение:

Это краткое введение в общие проблемы параллелизма в MySQL. В разных СУБД (PostgreSQL и т. Д.) Используются разные подходы к решению этих проблем параллелизма. Не существует универсального решения. Для решения этих проблем нам необходимо подробнее изучить документацию и реализацию каждой СУБД.

Спасибо, что дочитали до конца. Если есть неправильное заявление, пожалуйста, оставьте комментарий ниже. Очень признателен!

Ссылки:
https://medium.com/@chester.yw.chu/%E5%B0%8D%E6%96%BC-mysql-repeatable-read-isolation-%E5%B8%B8% E8% A6% 8B% E7% 9A% 84% E4% B8% 89% E5% 80% 8B% E8% AA% A4% E8% A7% A3-7a9afbac65af

Https://stackoverflow.com/questions/34510/what-is-a-race-condition

Https://blog.xuite.net/vexed/tech/22289223-%E7%94%A8+SELECT+...+FOR+UPDATE+%E9%81%BF%E5%85%8D+Race+condition