Back to questions
OZON
Senior
5
Приведи пример случая с SELECT FOR UPDATE, когда это может привести к deadlock.
Companies where asked
Answer from AI
sobes.tech AI
Deadlock с SELECT FOR UPDATE может возникнуть, когда два или более транзакций пытаются захватить блокировки на одни и те же строки, но в разном порядке.
Пример:
- Транзакция A выполняет
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;— блокирует строку с id=1. - Транзакция B выполняет
SELECT * FROM accounts WHERE id = 2 FOR UPDATE;— блокирует строку с id=2. - Транзакция A пытается выполнить
SELECT * FROM accounts WHERE id = 2 FOR UPDATE;— ждёт освобождения блокировки на id=2. - Транзакция 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.