Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти
Інше
Події Про нас

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):

  1. Додати нову колонку (nullable) - старий код працює.
  2. Задеплоїти код, що пише і в стару, і в нову.
  3. Перенести дані (фоновий job), перемкнути читання.
  4. Окремим релізом видалити стару колонку.

Практики:

  • Не покладатися на 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 можна прочитати застарілі дані.
  • Реплікація асинхронна → завжди закладайте можливе відставання реплік у логіці.

Докладніше в документації: Read/Write підключення