TGViewer
EvApps EvApps @evapps_team · 199 subscribers
Post #1481 154
Сегодня завершим нашу линейку постов про транзакции.

🚨 1) Внешние действия внутри транзакции = проблемы
Любой внешний вызов внутри транзакции может выполниться два и более раз, потому что Laravel автоматически повторяет транзакцию при дедлоках и таймаутах.
DB::transaction($callback, $attempts) сам делает retry, если произошёл:
- дедлок
- lock wait timeout
- потеря блокировки

И важно: При повторе он запускает весь callback с нуля.
Он не понимает, что там было «одноразовым», а что идемпотентным.

Что под раздачу попадает:
- отправка писем
- пуши
- внешние HTTP-запросы
- интеграции (CRM, платёжки)

Если транзакция упала и Laravel её перезапустил → действие повторится, потому что MySQL откатывает только свои изменения, а внешние вызовы уже произошли и не откатываются.
Как избежать:
- всё внешнее — только после commit
- использовать afterCommit() у моделей или dispatch(fn)->afterCommit() — так действие выполняется один раз, после успешной фиксации данных.

🔒 2) Дедлоки из-за порядка блокировок
Дедлок (deadlock) — ситуация, когда две и более транзакций ожидают друг друга бесконечно, и MySQL вынужден прервать одну из них, чтобы система продолжила работать.
Чаще всего дедлоки возникают не из-за MySQL как такового, а из-за разного порядка, в котором код блокирует строки или ресурсы.

Пример типичной ситуации:
- Транзакция A начинает и лочит строки 5 → 10
- Транзакция B начинает и лочит строки 10 → 5
MySQL обнаруживает тупик и прерывает одну транзакцию с ошибкой Deadlock found.

Как снизить риск:
1. Всегда блокировать строки в одном порядке
Обычно по возрастанию ID, чтобы исключить циклические ожидания.
$rows = DB::table('accounts')
->whereIn('id', [$id1, $id2])
->orderBy('id')
->lockForUpdate()
->get();

2. Использовать блокировки корректно
- FOR UPDATE — эксклюзивная блокировка для изменения
- sharedLock() — блокировка для чтения без мешающих других читателей
3. Минимизировать время удержания блокировок
Чем быстрее транзакция завершится, тем ниже шанс дедлока.
4. Разделять независимые операции
Операции по разным таблицам или сущностям лучше выполнять в отдельных транзакциях, чтобы не увеличивать зону возможного конфликта.

🌐 3) Когда транзакции не работают вообще
Стандартные транзакции работают только в рамках одной базы данных и одного соединения.
Если операция затрагивает:
- несколько сервисов (например, микросервисы с разной логикой),
- несколько БД (разные инстансы, разные схемы),
- внешние API (CRM, платёжные системы, сторонние интеграции),то гарантировать атомарность стандартной транзакцией невозможно.

Причина: транзакция контролирует только изменения внутри конкретного движка базы данных.
Внешние действия, например HTTP-запросы или вызовы другой БД, не могут быть откатаны автоматически при ошибке — их состояние уже “зафиксировано” в сторонней системе.

🔹4) Стандартный подход — Saga pattern
Saga pattern — это архитектурный паттерн для управления распределёнными транзакциями.
Его идея проста:
1.Каждый шаг — независимый
Каждое действие выполняется как отдельная транзакция, которая гарантированно сохраняет свои изменения в локальной БД.
2. Компенсирующие действия
Для каждого шага создаётся обратная операция, которая может откатить изменения, если последующий шаг не удался.
Например, для биллинга:
Шаг 1: резервируем средства на счёте клиента (локальная транзакция)
Шаг 2: создаём заказ в системе (локальная транзакция)
Шаг 3: уведомляем склад о сборкеЕсли шаг 2 падает, шаг 1 компенсируется: средства возвращаются на счёт клиента.

Преимущества Saga pattern:
- Нет необходимости в глобальной межсервисной транзакции, которая блокировала бы все сервисы.
- Процесс становится устойчивым к сбоям: каждая ошибка обрабатывается локально и компенсируется.
- Подходит для систем с высокой нагрузкой и распределённой архитектурой: очереди, биллинг, бронирования, логистика.

❓ Есть ли у вас интересные кейсы, когда Saga pattern спасала систему от ошибок?

#laravel #mysql #transactions #webdev #db #devops #saga #aftercommit
More from @evapps_team
  1. Sep 23, 2026🔁 Ретраи, которые добивают лежачий сервис Сервис-сосед начал тупить, отвечает через раз Л…
  2. Sep 23, 2026Хотите не теряться среди сотен откликов? На hh сейчас бывает ощущение, что до HR просто не…
  3. Sep 23, 2026photo post
  4. Sep 21, 2026🧩 Что тут не так? Код-загадка Формат новый - показываю код, ты угадываешь подвох, ниже ра…
  5. Sep 18, 2026🎭 Мифы про производительность, в которые верят даже опытные Миф 1: "Меньше строк кода - б…
  6. Sep 16, 2026🚨 Как перевод денег уронил нам прод ⏰ 19:10 Задеплоили долгожданное - переводы между коше…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →