Захватывайте блокировки в едином глобальном порядке, держите транзакции короткими, снижайте isolation там, где это безопасно, и повторяйте проигравшего, когда deadlock всё же случается. Deadlock — это цикл: транзакция A держит строку 1 и ждёт строку 2, а B держит строку 2 и ждёт строку 1 — ни одна не может продолжить, поэтому БД убивает одну.
Цикл, который нужно разорвать
Tx A Tx B
holds row 1 ──── waits ────▶ row 2 (held by B)
▲ │
│ waits │ holds
└────────── row 1 ◀────────────┘
(cycle = deadlock; DB aborts one victim)
