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