- Задание 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. А ТАКЖЕ УСЛОВИЕ, ЧТО БАЛАНС НЕ МОЖЕТ ОПУСКАТЬСЯ НИЖЕ НУЛЯ, ИНАЧЕ ОТКЛОНЕНИЕ ТРАНЗАКЦИИ.