> Зачем нужны блокировки в базе данных (PHP)
Уровень: senior · Роль: backend · Язык: PHP · Категория: Технические вопросы
Компании: vanta
Стек: PHP, Go
> Пример ответа
Короткий ответ
Блокировки в БД нужны для обеспечения согласованности данных при конкурентном доступе. Они предотвращают потерянные обновления, грязные чтения и фантомные записи. Без блокировок параллельные транзакции могут привести к некорректному состоянию базы, например, к двойному списанию средств или перезаписи чужих изменений. Блокировки - это базовый механизм изоляции транзакций, который позволяет балансировать между строгостью гарантий и производительностью.
Подробное объяснение
Блокировки решают проблему конкурентного доступа к одним и тем же данным. Когда несколько транзакций одновременно читают и пишут, возникают классические аномалии:
- Потерянное обновление - две транзакции читают одно значение, обе меняют, последняя запись затирает первую.
- Грязное чтение - чтение данных, которые ещё не закоммичены и могут быть откачены.
- Неповторяющееся чтение - в рамках одной транзакции одно и то же чтение даёт разные результаты.
- Фантомы - при повторном запросе появляются новые строки, добавленные другой транзакцией.
Уровни изоляции (READ COMMITTED, REPEATABLE READ, SERIALIZABLE) реализуются именно через блокировки или MVCC (multiversion concurrency control). В PostgreSQL и MySQL InnoDB используется MVCC, но блокировки всё равно применяются для write-write конфликтов и явных операций SELECT ... FOR UPDATE.
Блокировки бывают:
- Разделяемые (shared, S) - несколько читателей могут держать одновременно, писатели - нет.
- Эксклюзивные (exclusive, X) - только один держатель, никто другой не может ни читать, ни писать.
- На уровне строк, страниц, таблиц, БД - чем грубее гранулярность, тем меньше накладные расходы, но больше конфликтов.
- Оптимистичные и пессимистичные - первые проверяют конфликт при коммите, вторые блокируют заранее.
Важный trade-off: блокировки увеличивают время ожидания и риск deadlock'ов. Deadlock - когда две транзакции ждут блокировки друг друга. СУБД автоматически детектит и откатывает одну из них.
На практике
В PHP и Go при работе с БД блокировки используются в двух сценариях:
-
Явные блокировки строк через
SELECT ... FOR UPDATE- когда нужно атомарно прочитать и обновить данные в рамках бизнес-операции. Например, списание средств с баланса: без блокировки два параллельных запроса могут прочитать один и тот же баланс и оба записать уменьшенное значение. -
Неявные блокировки при записи - каждая
UPDATEилиDELETEберёт эксклюзивную блокировку на строку. Проблемы возникают, когда транзакция долго держит блокировку, например, при внешних HTTP-вызовах внутри транзакции.
В Go с database/sql и pgx важно помнить, что транзакция открывается явно, и блокировки держатся до commit/rollback. В PHP с PDO аналогично.
Типичный паттерн - optimistic locking через версионирование: добавляется колонка version, при обновлении проверяется WHERE version = ?, и если затронуто 0 строк - конфликт. Это дешевле пессимистичных блокировок для read-heavy нагрузок.
Пример кода
Пессимистичная блокировка строки в Go с pgx:
GOtx, err := db.Begin(ctx)if err != nil { /* handle */ }defer tx.Rollback(ctx)var balance interr = tx.QueryRow(ctx,"SELECT balance FROM accounts WHERE id = $1 FOR UPDATE",accountID,).Scan(&balance)if err != nil { /* handle */ }newBalance := balance - amount_, err = tx.Exec(ctx,"UPDATE accounts SET balance = $1 WHERE id = $2",newBalance, accountID,)if err != nil { /* handle */ }tx.Commit(ctx)
Оптимистичная блокировка в PHP с PDO:
PHP$pdo->beginTransaction();$stmt = $pdo->prepare("SELECT balance, version FROM accounts WHERE id = ?");$stmt->execute([$accountId]);$row = $stmt->fetch();$newBalance = $row['balance'] - $amount;$newVersion = $row['version'] + 1;$update = $pdo->prepare("UPDATE accounts SET balance = ?, version = ? WHERE id = ? AND version = ?");$update->execute([$newBalance, $newVersion, $accountId, $row['version']]);if ($update->rowCount() === 0) {$pdo->rollBack();throw new RuntimeException('Конфликт версий, повторите операцию');}$pdo->commit();
Как отвечать на собеседовании
Начни с цели - согласованность при конкурентном доступе. Затем перечисли аномалии, которые блокировки предотвращают. Упомяни уровни изоляции и связь с MVCC. Покажи понимание trade-off: блокировки vs производительность, deadlock'и. Приведи конкретный пример из практики - списание средств или заказ товара. Для senior важно показать, что ты знаешь, когда использовать пессимистичные блокировки, а когда оптимистичные, и как избегать долгих транзакций.
Что проверяет интервьюер
- Понимание модели изоляции транзакций и аномалий.
- Умение выбирать между пессимистичным и оптимистичным подходом.
- Знание гранулярности блокировок и их влияния на производительность.
- Осведомлённость о deadlock'ах и способах их обработки.
- Практический опыт: как блокировки ведут себя в конкретной СУБД (PostgreSQL, MySQL).
- Понимание, что блокировки - не серебряная пуля, и есть альтернативы (MVCC, атомарные операции, очереди).
Типичные ошибки
- Путаница между блокировками и транзакциями - блокировки не заменяют транзакции, а работают внутри них.
- Утверждение, что
SELECTне блокирует ничего - в зависимости от уровня изоляции и СУБД это не так. - Игнорирование deadlock'ов - "у нас их нет" обычно значит "мы не настроили таймауты и не логируем".
- Использование
SELECT ... FOR UPDATEбез необходимости - это убивает параллельность на read-heavy операциях. - Держать транзакцию открытой во время внешних вызовов (HTTP, API) - блокировки висят, растёт вероятность конфликтов.
- Не учитывать разницу между СУБД: в PostgreSQL
FOR UPDATEработает иначе, чем в MySQL с InnoDB.
> Похожие задачи по PHP
Что такое нормализация и денормализация баз данных
Что такое составной индекс и как он работает
Используете ли нативные SQL-запросы или ORM
Как хранятся индексы в массивах PHP
> Похожие задачи по backend
Что такое нормализация и денормализация баз данных
Что такое составной индекс и как он работает
Используете ли нативные SQL-запросы или ORM
Как хранятся индексы в массивах PHP
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью