Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# Read Committed — уровень изоляции транзакций
Read Committed — второй по строгости уровень изоляции транзакций в базах данных (согласно ANSI SQL), который обеспечивает баланс между производительностью и консистентностью данных.
Что такое Read Committed?
Read Committed гарантирует, что транзакция может читать только закоммиченные данные от других транзакций. Это означает, что вы не сможете прочитать грязные данные (dirty reads), которые ещё не были подтверждены.
Основные характеристики
Гарантии
- Запрещены грязные чтения (Dirty Reads) — не читаешь незакоммиченные данные других транзакций
- Разрешены неповторяемые чтения (Non-repeatable Reads) — одно и то же значение может измениться между двумя чтениями в одной транзакции
- Разрешены фантомы (Phantoms) — новые строки могут появиться между запросами
Механизм реализации
Обычно использует Row-level locks (блокировки на уровне строк):
// Транзакция A
BEGIN TRANSACTION;
SELECT salary FROM employees WHERE id = 1; // Читает закоммиченное значение
UPDATE employees SET salary = salary + 1000 WHERE id = 1;
COMMIT;
// Транзакция B (выполняется параллельно)
BEGIN TRANSACTION;
SELECT salary FROM employees WHERE id = 1; // Блокируется, пока A не закоммитит
COMMIT;
Почему Read Committed нужен?
1. Производительность
- Меньше блокировок, чем SERIALIZABLE
- Разрешает параллельное выполнение большинства операций
- В PostgreSQL это уровень по умолчанию
2. Консистентность
- Исключает грязные чтения
- Предотвращает потерю обновлений благодаря блокировкам при записи
3. Практическое применение
Большинство приложений требуют этого уровня:
@Transactional(isolation = Isolation.READ_COMMITTED)
public void transferMoney(Long fromAccount, Long toAccount, BigDecimal amount) {
Account from = accountRepo.findById(fromAccount).orElseThrow();
Account to = accountRepo.findById(toAccount).orElseThrow();
// Гарантия: читаем только закоммиченные остатки
if (from.getBalance().compareTo(amount) >= 0) {
from.setBalance(from.getBalance().subtract(amount));
to.setBalance(to.getBalance().add(amount));
}
}
Проблемы, которые не решает
Разберём на примере неповторяемого чтения:
// Транзакция 1
BEGIN TRANSACTION;
SELECT balance FROM accounts WHERE id = 1; // Результат: 1000
// ... какой-то код
SELECT balance FROM accounts WHERE id = 1; // Результат: 900 (изменилось!)
COMMIT;
// Параллельно выполнилась Транзакция 2
BEGIN TRANSACTION;
UPDATE accounts SET balance = 900 WHERE id = 1;
COMMIT;
В Read Committed это допускается. Если нужна защита от таких ситуаций, используй REPEATABLE_READ или SERIALIZABLE.
Сравнение с другими уровнями
| Уровень | Dirty Reads | Non-repeatable | Phantoms | Блокировки |
|---|---|---|---|---|
| READ_UNCOMMITTED | Да | Да | Да | Минимум |
| READ_COMMITTED | Нет | Да | Да | Средний |
| REPEATABLE_READ | Нет | Нет | Да | Много |
| SERIALIZABLE | Нет | Нет | Нет | Максимум |
Когда использовать?
-
Выбирай READ_COMMITTED, если:
- Нужна хорошая производительность
- Допустимы неповторяемые чтения
- Приложение может обработать изменения между двумя чтениями
-
Выбирай выше, если:
- Требуется строгая консистентность
- Бизнес-логика критична к состоянию данных
В большинстве случаев Read Committed — идеальный выбор для OLTP-приложений, обеспечивая баланс между безопасностью и производительностью.