added theory bd isolation level
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
- Задание 1: Разбери ситуацию
|
||||
|
||||
У тебя две транзакции работают с таблицей `accounts`:
|
||||
|
||||
**Транзакция A:**
|
||||
|
||||
BEGIN;
|
||||
SELECT balance FROM accounts WHERE id = 1; -- balance = 100
|
||||
-- ждёт 10 секунд
|
||||
SELECT balance FROM accounts WHERE id = 1; -- balance = ???
|
||||
COMMIT;
|
||||
|
||||
**Транзакция B (выполняется параллельно):**
|
||||
|
||||
BEGIN;
|
||||
UPDATE accounts SET balance = 200 WHERE id = 1;
|
||||
COMMIT;
|
||||
|
||||
**Вопросы:**
|
||||
|
||||
1. Какой баланс увидит транзакция A во втором SELECT на уровне **Read Committed**?
|
||||
УВИДИТ 200
|
||||
2. Какой баланс увидит транзакция A во втором SELECT на уровне **Repeatable Read**?
|
||||
УВИДИТ 100
|
||||
3. Объясни, почему результаты разные.
|
||||
ПОТОМУ ЧТО УРОВНИ ИЗОЛЯЦИИ РАЗНЫЕ, В ПЕРВОМ СЛУЧАЕ ВИДИМ ТОЛЬКО ЗАКОММИЧЕННЫЕ ДАННЫЕ, А ВО ВТОРОМ ТЕ ДАННЫЕ, КОТОРЫЕ БЫЛИ В САМОМ НАЧАЛЕ ТРАЗАКЦИИ.
|
||||
|
||||
- Задание 2: Практика
|
||||
|
||||
Создай таблицу:
|
||||
|
||||
CREATE TABLE test_isolation (id INT PRIMARY KEY, value INT);
|
||||
INSERT INTO test_isolation VALUES (1, 100);
|
||||
|
||||
Открой **две** вкладки в DBeaver.
|
||||
|
||||
**В первой вкладке:**
|
||||
|
||||
BEGIN;
|
||||
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
|
||||
SELECT value FROM test_isolation WHERE id = 1;
|
||||
|
||||
**Во второй вкладке:**
|
||||
|
||||
BEGIN;
|
||||
UPDATE test_isolation SET value = 200 WHERE id = 1;
|
||||
COMMIT;
|
||||
|
||||
**Обратно в первой вкладке:**
|
||||
|
||||
SELECT value FROM test_isolation WHERE id = 1;
|
||||
COMMIT;
|
||||
|
||||
**Вопрос:** Какое значение ты увидел во втором SELECT? Почему?
|
||||
УВИДЕЛ 100, ПОТОМУ ЧТО dbeaver В ПЕРВОЙ ТРАНЗАКЦИИ ПОДДЕРЖИВАЕТ Repeatable Read И ТРАНЗАКЦИЯ НЕ БЫЛА ЗАКОММИЧЕНА.
|
||||
|
||||
Повтори эксперимент с уровнем **Read Committed** вместо **Repeatable Read**. Что изменилось?
|
||||
В ДАННОМ СЛУЧАЕ ИЗМЕНИЛСЯ ТИП ИЗОЛЯЦИИ И ТК ВТОРАЯ ТРАЗАКЦИЯ БЫЛА ЗАКОМИЧЕНА, ТО ВЫВОД ТРЕТЬЕГО ЗАПРОСА ПОКАЗАЛ ИМЕННО ПОСЛЕДНЕЕ ЗАКОМИЧЕННОЕ.
|
||||
|
||||
- Задание 3: Найди ошибку
|
||||
|
||||
Вася написал код для списания денег со счёта:
|
||||
|
||||
BEGIN;
|
||||
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
|
||||
-- Проверяем баланс
|
||||
SELECT balance FROM accounts WHERE id = 1; -- balance = 100
|
||||
|
||||
-- Думаем 5 секунд (пользователь вводит сумму)
|
||||
|
||||
-- Списываем деньги
|
||||
UPDATE accounts SET balance = balance - 50 WHERE id = 1;
|
||||
|
||||
COMMIT;
|
||||
|
||||
**Проблема:** Пока Вася думал 5 секунд, другая транзакция списала 80 руб. Теперь баланс стал отрицательным
|
||||
|
||||
**Вопросы:**
|
||||
|
||||
1. Почему так произошло?
|
||||
ПОТОМУ ЧТО ВНУТРЬ ТРАНЗАКЦИИ ВОРВОЛАСЬ ДРУГАЯ, А UPDATE БЕРЕТ ЗНАЧЕНИЕ НА ДАННЫЙ МОМЕНТ. ЧТОБЫ ЭТОГО ИЗБЕЖАТЬ ВАСЕ НАДО БЫЛО В СВОЕЙ ТРАНЗАКЦИИ НАПИСТАЬЬ FOR UPDATE И ЕГО ЗНАЧЕНИЕ БЫ ЗАМОРОЗИЛОСЬ.
|
||||
|
||||
2. Какой уровень изоляции поможет избежать этой проблемы?
|
||||
Serializable
|
||||
3. Как ещё можно решить эту проблему без смены уровня изоляции? (подсказка: проверяй баланс перед UPDATE)
|
||||
КАК ВЫШЕ СКАЗАЛ МОЖНО ИСПОЛЬЗОВАТЬ FOR UPDATE. А ТАКЖЕ УСЛОВИЕ, ЧТО БАЛАНС НЕ МОЖЕТ ОПУСКАТЬСЯ НИЖЕ НУЛЯ, ИНАЧЕ ОТКЛОНЕНИЕ ТРАНЗАКЦИИ.
|
||||
Reference in New Issue
Block a user