Ответ
Уровни изоляции транзакций — это настройка в СУБД, которая определяет, насколько одна транзакция "видит" изменения, сделанные другими параллельными транзакциями. Чем выше уровень изоляции, тем надежнее защита от аномалий, но ниже производительность из-за использования блокировок.
Стандарт SQL определяет четыре основных уровня:
Read Uncommitted (Чтение незафиксированных данных)
- Что делает: Транзакция может читать данные, которые были изменены другой транзакцией, но еще не зафиксированы (не выполнен
COMMIT
). - Какие аномалии возможны: Грязное чтение (Dirty Read), неповторяющееся чтение (Non-Repeatable Read), фантомное чтение (Phantom Read).
- Что делает: Транзакция может читать данные, которые были изменены другой транзакцией, но еще не зафиксированы (не выполнен
Read Committed (Чтение зафиксированных данных)
- Что делает: Транзакция видит только те изменения, которые были зафиксированы другими транзакциями до ее начала.
- Какие аномалии предотвращает: Грязное чтение.
- Какие аномалии возможны: Неповторяющееся чтение, фантомное чтение.
- Это уровень по умолчанию во многих СУБД, например, в PostgreSQL и Oracle.
Repeatable Read (Повторяемое чтение)
- Что делает: Гарантирует, что если одна и та же строка читается несколько раз в рамках одной транзакции, результат будет одинаковым.
- Какие аномалии предотвращает: Грязное чтение, неповторяющееся чтение.
- Какие аномалии возможны: Фантомное чтение.
- Это уровень по умолчанию в MySQL (InnoDB).
Serializable (Сериализуемый)
- Что делает: Полностью изолирует транзакции друг от друга. Результат параллельного выполнения транзакций эквивалентен их последовательному выполнению.
- Какие аномалии предотвращает: Все: грязное чтение, неповторяющееся чтение и фантомное чтение.
- Цена: Самый низкий уровень параллелизма и производительности.
В Go уровень изоляции можно указать при создании транзакции с помощью пакета database/sql
:
import (
"context"
"database/sql"
)
// ... db *sql.DB ...
ctx := context.Background()
// Начинаем транзакцию с уровнем изоляции Serializable
tx, err := db.BeginTx(ctx, &sql.TxOptions{
Isolation: sql.LevelSerializable,
})
if err != nil {
// обработка ошибки
}
// ... работа с транзакцией tx ...