При параллельном выполнении транзакций могут возникать следующие аномалии:
Потерянное обновление (Lost Update): Одна транзакция перезаписывает изменения другой транзакции до того, как эти изменения были зафиксированы.
| Время | Транзакция 1 | Транзакция 2 |
|---|---|---|
| t1 | Читает значение Валанс (например, 100) | |
| t2 | Читает значение Валанс (например, 100) | |
| t3 | Увеличивает Валанс на 10 (Валанс = 110) | |
| t4 | Увеличивает Валанс на 20 (Валанс = 120) | |
| t5 | Фиксирует изменения (Валанс становится 110) | |
| t6 | Фиксирует изменения (Валанс становится 120) |
Результат: Несмотря на два увеличения, конечное значение Валанс равно 120, а не 130. Увеличение от Транзакции 1 потеряно.
Грязное чтение (Dirty Read): Одна транзакция читает незафиксированные изменения другой транзакции. Если транзакция, сделавшая изменения, откатится, прочитанные данные окажутся недействительными.
| Время | Транзакция 1 | Транзакция 2 |
|---|---|---|
| t1 | Начинает изменение Валанс (100 -> 110) | |
| t2 | Читает Валанс (получает 110) | |
| t3 | Откатывает изменение (Валанс возвращается к 100) | |
| t4 | Использует Валанс = 110 в расчетах, хотя фактическое значение 100 |
Результат: Транзакция 2 основывает свои действия на данных, которые в конечном итоге не были зафиксированы.
Неповторяющееся чтение (Non-Repeatable Read): В течение одной транзакции при повторном чтении одной и той же строки получаются разные значения, потому что другая транзакция зафиксировала изменения этой строки между чтениями.
| Время | Транзакция 1 | Транзакция 2 |
|---|---|---|
| t1 | Читает Валанс (получает 100) | |
| t2 | Изменяет Валанс на 110 и фиксирует | |
| t3 | Снова читает Валанс (получает 110 вместо ожидаемых 100) |
Результат: Валанс изменился в рамках одной и той же транзакции, что может привести к некорректным результатам.
Фантомное чтение (Phantom Read): Похоже на неповторяющееся чтение, но касается не изменения существующих строк, а добавления или удаления строк, которые влияют на результаты запроса с предикатом.
| Время | Транзакция 1 | Транзакция 2 |
|---|---|---|
| t1 | Выполняет запрос SELECT COUNT(*) FROM Orders WHERE Status = 'Pending' (получает 5) | |
| t2 | Добавляет новую заявку со статусом 'Pending' и фиксирует | |
| t3 | Снова выполняет SELECT COUNT(*) FROM Orders WHERE Status = 'Pending' (получает 6) |
Результат: При повторном выполнении запроса появляются "фантомные" строки, которых не было при первом чтении.
Эти аномалии предотвращаются использованием различных уровней изоляции транзакций.