Senior: питання на співбесіді з теми «Database»
Найпопулярніші питання з реальних Laravel/PHP співбесід для всіх рівнів
4 питання
Pessimistic locking блокує рядок у БД до завершення транзакції - інші транзакції чекають.
DB::transaction(function () {
$account = Account::lockForUpdate()->find($id); // блокування на запис
$account->balance -= 100;
$account->save();
});
sharedLock() - блокування на читання.
Optimistic locking не блокує, а перевіряє версію/updated_at перед записом; якщо хтось уже змінив рядок - оновлення відхиляється, операцію повторюють.
UPDATE accounts SET balance = ?, version = version + 1
WHERE id = ? AND version = ?
- Pessimistic - для високої конкуренції за тими ж рядками (платежі, склад).
- Optimistic - коли конфлікти рідкісні; масштабується краще, бо не тримає блокувань.
Deadlock - дві транзакції взаємно блокують одна одну, чекаючи на ресурси, які тримає інша. СУБД виявляє це й «вбиває» одну з транзакцій.
Запобігання:
- Єдиний порядок доступу до таблиць/рядків у всіх транзакціях.
- Тримати транзакції короткими, блокувати якомога пізніше.
- Правильні рівні ізоляції (не завищувати без потреби).
Обробка в Laravel - автоматичний повтор:
DB::transaction(function () {
// ...
}, attempts: 3); // повторити при deadlock
Діагностика: SHOW ENGINE INNODB STATUS (MySQL), логи БД, моніторинг частоти deadlock. Інколи допомагає optimistic locking замість тривалих блокувань.
Головний ризик - несумісність схеми зі старим кодом під час деплою та блокування таблиць.
Безпечні зміни (expand → migrate → contract):
- Додати нову колонку (nullable) - старий код працює.
- Задеплоїти код, що пише і в стару, і в нову.
- Перенести дані (фоновий job), перемкнути читання.
- Окремим релізом видалити стару колонку.
Практики:
- Не покладатися на
migrate:rollbackу проді -down()може втрачати дані. Краще forward-fix. - Великі
ALTERна величезних таблицях блокують → онлайн-міграції (pt-online-schema-change, gh-ost). php artisan migrate --forceу пайплайні;--isolated, щоб не виконати паралельно на кількох воркерах.- Бекап перед руйнівними операціями; прогін міграцій на staging.
Реплікація розвантажує основний сервер: запис іде на primary, читання - на replicas. Laravel маршрутизує запити автоматично, якщо в конфізі з'єднання задані секції read/write:
'mysql' => [
'read' => ['host' => ['10.0.0.2', '10.0.0.3']], // репліки
'write' => ['host' => ['10.0.0.1']], // primary
'sticky' => true,
// ...спільні параметри
],
SELECT→ репліка,INSERT/UPDATE/DELETE→ primary.sticky => trueкритично важливе: після запису в межах того ж запиту читання теж піде з primary, інакше через replication lag можна прочитати застарілі дані.- Реплікація асинхронна → завжди закладайте можливе відставання реплік у логіці.