Ответ
Repeatable Read — это один из стандартных уровней изоляции транзакций в базах данных. Он гарантирует, что если в рамках одной транзакции несколько раз прочитать одни и те же строки, результат будет одинаковым.
По сути, транзакция работает со «снимком» данных, сделанным на момент её начала. Изменения, закоммиченные другими транзакциями после старта текущей, не будут видны.
От каких аномалий защищает:
- Dirty Read (Грязное чтение): Чтение данных, которые были изменены другой транзакцией, но еще не закоммичены. Repeatable Read полностью предотвращает это.
- Non-Repeatable Read (Неповторяющееся чтение): Ситуация, когда при повторном чтении в одной транзакции одна и та же строка возвращает разные данные (т.к. другая транзакция успела их изменить и закоммитить). Repeatable Read решает эту проблему.
Какую проблему НЕ решает:
- Phantom Read (Фантомное чтение): Ситуация, когда при повторном чтении диапазона строк в одной транзакции обнаруживаются новые строки, которые были добавлены и закоммичены другой транзакцией. Например,
SELECT COUNT(*) FROM users WHERE age > 30
может вернуть разные результаты.
Пример на Go (с database/sql
и PostgreSQL):
// Начинаем транзакцию с нужным уровнем изоляции
tx, err := db.BeginTx(ctx, &sql.TxOptions{
Isolation: sql.LevelRepeatableRead,
})
if err != nil {
log.Fatal(err)
}
// defer tx.Rollback() — хорошая практика для отката в случае ошибок
defer tx.Rollback()
// Первое чтение
var balance int
tx.QueryRow("SELECT balance FROM accounts WHERE id = 1").Scan(&balance)
fmt.Println("First read:", balance) // Например, 1000
// Представим, что в этот момент другая транзакция изменила баланс на 500 и закоммитила изменения
// Повторное чтение в НАШЕЙ транзакции
var newBalance int
tx.QueryRow("SELECT balance FROM accounts WHERE id = 1").Scan(&newBalance)
fmt.Println("Second read:", newBalance) // Все равно будет 1000
// Завершаем транзакцию
err = tx.Commit()
Этот уровень является хорошим компромиссом между производительностью и консистентностью, сильнее чем Read Committed
, но слабее Serializable
.