Sobes.tech
Назад к вопросам
Senior
6

Приведи пример случая с SELECT FOR UPDATE, когда это может привести к deadlock.

Компании, где спрашивали
OZONOZON

Ответ от нейросети

sobes.tech AI

Deadlock с SELECT FOR UPDATE может возникнуть, когда два или более транзакций пытаются захватить блокировки на одни и те же строки, но в разном порядке.

Пример:

  1. Транзакция A выполняет SELECT * FROM accounts WHERE id = 1 FOR UPDATE; — блокирует строку с id=1.
  2. Транзакция B выполняет SELECT * FROM accounts WHERE id = 2 FOR UPDATE; — блокирует строку с id=2.
  3. Транзакция A пытается выполнить SELECT * FROM accounts WHERE id = 2 FOR UPDATE; — ждёт освобождения блокировки на id=2.
  4. Транзакция B пытается выполнить SELECT * FROM accounts WHERE id = 1 FOR UPDATE; — ждёт освобождения блокировки на id=1.

В итоге обе транзакции ждут друг друга, возникает deadlock.

Чтобы избежать таких ситуаций, нужно:

  • Всегда блокировать строки в одном и том же порядке.
  • Минимизировать время удержания блокировок.
  • Использовать таймауты или обработку ошибок deadlock.

Пример кода на Go с использованием транзакций и SELECT FOR UPDATE:

tx1, _ := db.Begin()
// Транзакция 1 блокирует account 1
row1 := tx1.QueryRow("SELECT balance FROM accounts WHERE id = 1 FOR UPDATE")

// В другом горутине или процессе:
tx2, _ := db.Begin()
// Транзакция 2 блокирует account 2
row2 := tx2.QueryRow("SELECT balance FROM accounts WHERE id = 2 FOR UPDATE")

// Если tx1 теперь попытается заблокировать account 2, а tx2 — account 1, будет deadlock

Таким образом, deadlock возникает из-за перекрёстных блокировок при использовании SELECT FOR UPDATE.