✉️ Пост 43. Блокировки в БД и конкурентный доступ. Общее инфо Представь ситуацию: два сервиса одновременно работают с одной и той же записью.
Например: ⚪️ сервис A списывает деньги ⚪️ сервис B тоже пытается списать деньги ⚪️ оба читают баланс = 100 И если ничего не контролить - получится хаос: оба спишут по 100 баланс станет -100 🗿
Чтобы этого не происходило, в БД существуют механизмы блокировок и контроля конкурентности.
🧠 Что такое блокировки Блокировка - это механизм, который ограничивает доступ к данным, чтобы избежать конфликтов при одновременной работе. Если проще: кто-то "захватил" данные остальные либо ждут, либо читают по особым правилам
❓**Какие бывают блокировки:
🔹 Shared lock (S-lock) - на чтение** Когда транзакция читает данные: SELECT * FROM users WHERE id = 1 она может поставить shared lock. Что это: ⚪️ Другие тоже могут читать ⚪️ но никто не может писать Это режим "читаем вместе, но не трогаем"
🔹 Exclusive lock (X-lock) - на запись Когда кто-то обновляет данные: UPDATE users SET balance = 0 WHERE id = 1 ставится exclusive lock. Что это: ⚪️ никто не может читать (в некоторых режимах) ⚪️ никто не может писать - все ждут Это режим "я тут один".
⚙️ Как это работает под капотом Когда транзакция делает запрос: 1️⃣ БД определяет, какие строки затронуты 2️⃣ ставит на них lock 3️⃣ хранит информацию о блокировке в lock table 4️⃣ другие транзакции проверяют, можно ли им работать с этими данными Если нельзя - они ИЛИ:
- ждут
- получают ошибку
- читают старую версию данных
❓ Уровни блокировок Блокировки могут быть: ⚪️ на строку (row-level) ⚪️ на страницу (page-level) ⚪️ на таблицу (table-level)
❓ Как несколько сервисов читают одну запись Вот тут самое интересное. В современных БД почти всегда используется: MVCC (Multi-Version Concurrency Control) - о ней кратко дальше и поговорим ❓ Что такое MVCC MVCC - это механизм, при котором БД хранит несколько версий одной и той же строки. То есть: вместо того чтобы блокировать чтение, БД просто показывает тебе "свою версию данных".
📦 Пример Допустим есть запись: balance = 100 Транзакция A делает: UPDATE users SET balance = 50 Но commit ещё не произошёл. Кто что видит:
- транзакция A → 50
- транзакция B → 100, так как B читает старую версию строки.
⚡️ Что это даёт - чтение не блокируется
- запись не блокирует чтение
- высокая конкурентность Это причина, почему современные БД работают быстро.
🧨 Но блокировки никуда не деваются все равно MVCC не отменяет блокировки полностью. Они всё ещё нужны:
🔹 при UPDATE/DELETE Чтобы два процесса не изменили строку одновременно.
🔹 при SELECT FOR UPDATE SELECT * FROM users WHERE id = 1 FOR UPDATE Это явная блокировка. Говорит: "я собираюсь менять эту строку, не трогайте её".
⚠️ **Проблемы конкурентности:
-
Dirty read** Чтение незакоммиченных данных.
-
Non-repeatable read Два раза прочитал - получил разные значения.
-
Phantom read Появились новые строки в выборке.
📌 Уровни изоляции Чтобы контролировать проблемы конкурентности, есть уровни изоляции, но об этом в следующих постах)