Какие уровни изоляции транзакций существуют и как они влияют на работу базы данных?

Как можно улучшить структуру и ясность вопроса:

1) Как поведет себя UPDATE запрос в данной функции, если выполнение кода не дошло до этого запроса, будет ли он доступен для других запросов из других частей кода?

2) При запуске функции sameFunc одновременно несколькими пользователями, будет ли каждый пользователь ждать завершения предыдущих транзакций других пользователей?

3) Если все запросы в транзакции взаимодействуют только с полями конкретного пользователя, как это нужно правильно реализовать в транзакциях? Какой объект отвечает за транзакции, и каким образом он устанавливается для каждого пользователя в Node.js?
  • 1 февраля 2024 г. 12:09
Ответы на вопрос 3
Уровни изоляции транзакций определяют, как транзакции видят изменения, сделанные другими транзакциями и как они влияют на возможность возникновения определенных аномалий параллелизма, таких как "грязное чтение" (dirty read), "неповторяющееся чтение" (non-repeatable read), и "фантомное чтение" (phantom read). Существует четыре стандартных уровня изоляции транзакций:

1. `READ UNCOMMITTED` – самый низкий уровень изоляции, который позволяет транзакциям видеть незафиксированные изменения сделанные другими транзакциями. Это может привести к грязному чтению.

2. `READ COMMITTED` – уровень, при котором одна транзакция не видит незафиксированные изменения других. Предотвращает грязное чтение, но не неповторяющееся чтение.

3. `REPEATABLE READ` – предотвращает грязное и неповторяющееся чтение. Однако, возможны фантомные чтения.

4. `SERIALIZABLE` – самый высокий уровень изоляции, который предотвращает все вышеуказанные виды чтения, но может значительно снизить производительность из-за блокировок.

По поводу улучшения структуры и ясности вопросов:

1) "Если выполнение кода приостановлено перед UPDATE запросом в транзакции, будут ли вносимые изменения видны для других запросов во время паузы?"

2) "В случае одновременного запуска функции sameFunc разными пользователями, продолжат ли последующие пользователи ожидание до завершения транзакций, инициированных предыдущими пользователями?"

3) "Когда транзакция взаимодействует исключительно с данными, принадлежащими определенному пользователю, как организовать ее правильно? Какой компонент системы управляет транзакциями в Node.js, и каким образом он может быть настроен для индивидуальной обработки данных каждого пользователя?"

Ответы на ваши вопросы зависят от используемой системы управления базами данных (СУБД) и от вашего конкретного окружения и требований. В Node.js, транзакции обычно управляются с помощью клиента СУБД (например, `pg` для PostgreSQL, `mysql` для MySQL и т.д.). Каждый клиент предоставляет API для начала, управления и завершения транзакций. Вы можете настроить уровень изоляции транзакций в соответствии с вашими потребностями, используя соответствующие параметры в SQL-запросах или методы API клиента.
1) Что будет с запросом UPDATE, если исполнение кода ещё не дошло до этого запроса, оно получается будет ещё доступна для запросов из другого кода?

Не понял, что имеется ввиду. Но если это про то - "будут ли видны изменения, которые сделаны до вызова этого UPDATE в транзакции", то это зависит от уровня изоляции других транзакций.
В случае SERIALIZABLE - нет, не увидят.
2) А если функцию sameFunc запустят много юзеров? Получается КАЖДЫЙ юзер будет ждать завершения предыдущих транзакций от всех остальных юзеров?

Так как указана SERIALIZABLE, то да:
- Если конфликтов не будет, т.е. никто не обновлял те же самые записи, то будут ждать
- Если кто-то одновременно обновил одни и те же данные, то будет конфликт транзакции

Стоит еще учесть, что если одна и та же запись обновлена одновременно разными транзакциями, то поздняя транзакция просто заблокируется и будет ждать: либо когда первая закоммит - тогда конфликт транзакции, либо первая выполнит откат и ты продолжишь выполнение
P.S. еще есть таймаут ожидания транзакции

3) А если все запросы в транзакции взаимодействуют только с полями конкретного юзера, то как это нужно реализовать в транзакциях? Вроде как объект транзакции один — сам node.js, который единожды подключается к БД.

А вот тут надо разобраться. Зависит от того как ты работаешь с БД.
Судя по названию ты используешь пул соединений (переменная pool ) и каждый раз выполняешь запрос на нем. Я не знаю node.js и фреймворк для БД, который ты используешь, но что-то подсказывает, что на каждый такой .query создается отдельное подключение и выполняется запрос.
Если да, то этот код работать не будет, т.к. ты постоянно открываешь новое соединение, начинаешь транзакцию или запрос и закрываешь соединение. В этом случае, все начавшиеся транзакции завершатся сразу, а запросы, которые должны работать в транзакции будут выполняться сразу.
Чтобы все работало корректно - на каждом вызове этого метода открывай новое соединение и работай с ним. Тогда гонки в коде не будет. (Можно еще использовать пул соединений).

Дополнительно я бы еще реализовал логику повторных попыток выполнения, если был обнаружен конфликт транзакций (проверяй исключение)
Давайте рассмотрим ваши вопросы, относящиеся к работе транзакций и уровням изоляции в Node.js с использованием PostgreSQL: 

1. Влияние на запрос UPDATE до его выполнения:
Когда вы устанавливаете уровень изоляции транзакции как SERIALIZABLE, это означает, что транзакция обрабатывается так, как если бы она выполнялась последовательно. То есть, до того как вы не выполните запрос UPDATE, данные, которые вы собираетесь изменить, блокируются для других транзакций, которые пытаются их изменить. Это означает, что если другая транзакция попытается выполнить UPDATE на тех же данных, она будет заблокирована до тех пор, пока ваша транзакция не завершится коммитом или откатом.

2. Запуск функции sameFunc многими пользователями: Да, если множество пользователей запустят sameFunc, каждая из их транзакций будет ожидать завершения предыдущих транзакций, которые затрагивают те же данные. Это может привести к значительным задержкам и проблемам с производительностью, особенно если ваши вычисления занимают много времени. Уровень изоляции SERIALIZABLE обеспечивает строгую последовательность выполнения, что может быть не всегда желательно в высоконагруженных системах.

3. Работа с данными конкретного пользователя: Если все запросы в транзакции взаимодействуют только с данными определенного пользователя, то вы можете рассмотреть использование более низкого уровня изоляции, например READ COMMITTED, чтобы уменьшить вероятность блокировок. В этом случае, если разные транзакции взаимодействуют с разными пользователями, они не будут блокировать друг друга. Тем не менее, важно понимать, что при более низком уровне изоляции увеличивается вероятность возникновения таких явлений, как "неповторяющиеся чтения" или "фантомные чтения".

Для оптимизации работы с транзакциями в вашем случае, возможно, стоит рассмотреть следующие моменты:

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