Ответ
Уровни изоляции транзакций определяют, насколько транзакции изолированы друг от друга, балансируя между целостностью данных и производительностью. Стандарт SQL определяет четыре уровня (от наименее строгого к наиболее строгому):
-
READ UNCOMMITTED
- Проблема: Грязное чтение (Dirty Read). Транзакция может видеть незафиксированные изменения другой транзакции.
- Использование: Крайне редко, из-за риска увидеть данные, которые могут быть откатаны.
-
READ COMMITTED
- Решает: Грязное чтение. Транзакция видит только зафиксированные данные.
- Проблемы: Неповторяемое чтение (Non-repeatable Read) и фантомное чтение (Phantom Read). Между двумя чтениями одной строки в транзакции другая транзакция может изменить или удалить эту строку.
- По умолчанию во многих СУБД (PostgreSQL, Oracle).
-
REPEATABLE READ
- Решает: Грязное и неповторяемое чтение. Гарантирует, что строки, прочитанные в транзакции, не изменятся.
- Проблема: Фантомное чтение. Могут появиться новые строки, удовлетворяющие условию запроса.
- По умолчанию в MySQL (InnoDB).
-
SERIALIZABLE
- Решает: Все проблемы (грязное, неповторяемое, фантомное чтение). Самый строгий уровень.
- Механизм: Транзакции выполняются так, как если бы они шли последовательно. Часто реализуется через блокировки диапазонов.
- Недостаток: Наибольшее влияние на производительность и параллелизм.
Пример настройки в Node.js с использованием клиента pg для PostgreSQL:
const { Client } = require('pg');
const client = new Client();
await client.connect();
// Установка уровня изоляции для транзакции
await client.query('BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ');
try {
await client.query('UPDATE accounts SET balance = balance - 100 WHERE id = 1');
await client.query('UPDATE accounts SET balance = balance + 100 WHERE id = 2');
await client.query('COMMIT');
} catch (err) {
await client.query('ROLLBACK');
throw err;
}
Выбор уровня зависит от требований к согласованности данных и допустимых компромиссов в конкретном сценарии приложения.