Найти в Дзене

Exclusive внутри транзакции: что это и зачем

Скорее всего, если вы работали с базами данных и транзакциями, то замечали в коде transaction(exclusive = true). Сегодня как раз разберёмся, а что же это за exclusive. Представим, что у нас много-много-много котиков. Мы хотим их покормить, но при этом важно, чтобы никто другой в это время не кормил их. А то котики могут стать слишком толстыми и нездоровыми. Чтобы этого не произошло мы говорим всем: "Сейчас я кормлю котиков, и пока я это делаю, никто другой не может ни кормить, ни даже заглядывать в миски." Это похоже на установку exclusive = true в транзакции: мы полностью контролируем процесс, и никто больше не может вмешаться, пока мы не закончим. Это гарантирует, что все котики накормлены правильно, а миски не остаются в странном состоянии, где корма не хватает или, наоборот, слишком много. Т.е. когда мы ставим флаг exclusive = true в транзакции, то СУБД не будет разрешать другим транзакциям читать или изменять данные, с которыми работает текущая транзакция. Это гарантирует, что да
Оглавление

Скорее всего, если вы работали с базами данных и транзакциями, то замечали в коде transaction(exclusive = true). Сегодня как раз разберёмся, а что же это за exclusive.

exclusive = true

Представим, что у нас много-много-много котиков. Мы хотим их покормить, но при этом важно, чтобы никто другой в это время не кормил их. А то котики могут стать слишком толстыми и нездоровыми. Чтобы этого не произошло мы говорим всем: "Сейчас я кормлю котиков, и пока я это делаю, никто другой не может ни кормить, ни даже заглядывать в миски."

Это похоже на установку exclusive = true в транзакции: мы полностью контролируем процесс, и никто больше не может вмешаться, пока мы не закончим. Это гарантирует, что все котики накормлены правильно, а миски не остаются в странном состоянии, где корма не хватает или, наоборот, слишком много.

Т.е. когда мы ставим флаг exclusive = true в транзакции, то СУБД не будет разрешать другим транзакциям читать или изменять данные, с которыми работает текущая транзакция. Это гарантирует, что данные будут изменяться атомарно. Если в другой транзакции попытаются работать с теми же данными, система заблокирует их доступ до завершения текущей транзакции.

Особенности работы эксклюзивных блокировок

  • Представим, что у нас большая семья, и все хотят покормить котиков одновременно. Но мы сказали: "Кормить котиков можно только по одному!" Теперь остальные "помощники" стоят в очереди и ждут, пока мы закончим. Это замедляет процесс, особенно если людей много и они хотят покормить одних и тех же котиков. Т.е. такие блокировки могут замедлять работу, так как другие транзакции будут вынуждены ждать освобождения блокировки.
  • Deadlock: представим, что мы кормим серых котиков, а отец пошел кормить рыжих. Но потом мы решили, что хотим еще и рыжих покормить, а отец в это время захотел заняться серыми. В итоге оба ждем друг друга, и в итоге никто не может ничего сделать. В таких случаях приходится выбирать, кто уступит и остановится. Т.е. если несколько транзакций пытаются заблокировать ресурсы в противоположном порядке, это может привести к взаимной блокировке, где каждая транзакция ждет освобождения ресурса, который занят другой.
  • Эксклюзивный доступ гарантирует, что никто не начнет разбрасывать корм по мискам, пока мы этим занимаемся. Так котики всегда получают ровно то, что им приготовили, а корм в мисках находится под полным контролем. Т.е. использование эксклюзивных блокировок помогает обеспечить целостность данных, так как гарантируется, что только одна транзакция может изменять заблокированные данные.

Когда использовать эксклюзивные транзакции?

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

Итого, используем, если:

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

Когда избегать эксклюзивных блокировок?

  1. Если нужно обрабатывать много запросов одновременно: частое использование может сильно замедлить производительность.
  2. Чем дольше транзакция удерживает эксклюзивную блокировку, тем выше риск взаимных блокировок. Стоит учитывать это при разработке, чтобы транзакции выполнялись быстро.

exclusive = false

Представим, что у нас много-много-много котиков. Мы хотим их покормить, но тут мы говорим: "Кормим котиков все вместе, кто как успевает", — это значит, что мы не запрещаешь нашей семье подходить к мискам, пока сами кормим.

  1. Кто-то ещё может одновременно добавлять корм в те же миски, что и мы. Например, мы кладем немного сухого корма, а кто-то добавляет туда влажный. Все происходит параллельно, и никто никого не ждет.
  2. Никто не устанавливает строгих правил вроде "не подходи, пока я не закончу". Это ускоряет процесс, но есть риск, что кто-то случайно перекормит котика или положит не тот корм, потому что все работают одновременно.

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

Т.е. когда параметр exclusive установлен в значение false, транзакция может работать с данными параллельно с другими транзакциями. Они могут читать и изменять те же данные, с которыми работает текущая транзакция, пока она еще не завершена.

Что происходит в случае exclusive = false?

Если мы говорим: "Котики спокойные, можно всем подходить к мискам, кто хочет", — это значит, что мы не ограничиваем доступ друг друга к тем же мискам. Это отлично работает, если нам просто нужно проверить, сколько корма осталось, или посмотреть, поели ли котики. Никто не мешает друг другу, и процесс идет быстро. Мы не заморачиваемся с очередностью. Например, неважно, кто первым посмотрел миски — главное, что каждый получил нужную информацию.

Если мы все одновременно начинаем работать с мисками, могут возникнуть проблемы:

  1. Грязное чтение: представим, что один из нас добавляет корм в миску, но еще не закончил. В это время другой заглядывает и видит, что корм уже в миске, хотя на самом деле он еще не разложен как надо. В итоге можно сделать вывод, что миска заполнена, хотя это не так. Т.е. транзакция может прочитать данные, которые были изменены другой транзакцией, но еще не были зафиксированы (это может привести к некорректному состоянию).
  2. Фантомные чтения: представим, что один из нас уже поменял корм в миске, а другой еще не успел это заметить. Он начинает добавлять корм, думая, что работает с прежним состоянием, и в итоге миска оказывается перегруженной (котик, конечно, доволен, а вот мы нет). Т.е. при изменении данных одной транзакцией другая может наблюдать непредсказуемое состояние данных.

Когда использовать exclusive = false?

  1. Чтение данных: Если мы просто смотрим, сколько корма осталось в мисках, и не собираемся их менять, нет смысла запрещать друг другу это делать. Мы можем одновременно проверять миски, что экономит время и не мешает остальным. Т.е. если транзакция только читает данные и не изменяет их, то не нужно блокировать их для других транзакций. Это повышает производительность и позволяет другим транзакциям работать с данными.
  2. Когда неважно блокировать доступ: если каждый из нас добавляет корм в отдельные миски и не трогает миски других, блокировать доступ не нужно. Например, мы кормим разные группы котиков, и наши действия никак не пересекаются — всё работает без конфликтов. Т.е. если изменения данных могут выполняться независимо, и конфликты между транзакциями не приведут к серьезным последствиям.
  3. Высокая производительность: если важно работать быстро, например, когда у нас мало времени, мы можем разрешить всем одновременно подходить к мискам. Это ускоряет процесс, особенно если нет сложных зависимостей и риска путаницы. Т.е. в ситуациях, когда важно минимизировать время работы транзакции и ускорить доступ к данным.

Дубль статей в телеграмме — https://t.me/android_junior

Мои заметки в телеграмме — https://t.me/android_junior_notes