petushok55
@petushok55
Обучаюсь на практике.

Как работают транзакции, уровни изоляции в данном случае?

Node.js, PostgreSQL.
Допустим есть
такой код

function async sameFunc(){
    try {
        await pool.query('BEGIN');
        await pool.query('SET TRANSACTION ISOLATION LEVEL SERIALIZABLE');

        // здесь запросы SELECT в БД

        // далее сложные и долгие вычисления

        // затем UPDATE запрос в БД

        await pool.query('COMMIT'); // завершаем транзу
    } catch (err) {
        // В случае ошибки, откатываем транзакцию
        await pool.query('ROLLBACK');
        throw err;
    } finally {
        return;
    }
}



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

1) Что будет с запросом UPDATE, если исполнение кода ещё не дошло до этого запроса, оно получается будет ещё доступна для запросов из другого кода?

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

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

Не смог найти инфу об этом в сети, так как даже не знаю как правильно вопрос задать в этом случае
  • Вопрос задан
  • 98 просмотров
Решения вопроса 1
AshBlade
@AshBlade
Просто хочу быть счастливым
1) Что будет с запросом UPDATE, если исполнение кода ещё не дошло до этого запроса, оно получается будет ещё доступна для запросов из другого кода?

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

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

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

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

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

Дополнительно я бы еще реализовал логику повторных попыток выполнения, если был обнаружен конфликт транзакций (проверяй исключение)
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы