Проблема, о которой вы рассказываете, может возникать по нескольким причинам, однако в первую очередь стоит обратить внимание на особенности работы с блокировками и транзакциями в MySQL, а также на возможность состояния гонки между двумя процессами.
Вот несколько возможных причин и направлений для решения:
1. **Дублирование транзакций**: Убедитесь, что никакой другой код не выполняет обновление той же строки одновременно. Проверьте, что другие транзакции не запускаются на вашем стороне, которые могут создавать свои собственные блокировки или проблемы. Убедитесь, что у вас нет места, где несколько отдельных транзакций могут взаимодействовать с одной и той же записью.
2. **Параметры уровня изоляции**: В вашем случае уровень изоляции по умолчанию, а именно `REPEATABLE READ`, это нормальный выбор для работы с блокировками. Однако в некоторых случаях может потребоваться использовать более строгий уровень изоляции, такой как `SERIALIZABLE`. Это может помочь предотвратить ситуацию гонки.
3. **После обновления данных другим процессом**: Если другой процесс действительно модифицирует строку после вашего блока `SELECT FOR UPDATE`, он может сделать это до вашего `commit()`, если он завершает свою транзакцию до того, как ваша транзакция достигает `commit()`. Обратите внимание на порядок операций.
4. **Убедитесь, что lock-ы не "падают"**: Проверьте, возможно ли, что блокировка на строке снята перед завершением вашей транзакции. Это может произойти, если в процессе выполнения вашей транзакции происходит какой-то неявный `commit` или `rollback`.
5. **Возможность вложенных транзакций**: Если в `afterSave` у вас выполняются операции, которые открывают свои собственные транзакции, убедитесь, что они не вмешиваются в вашу основную транзакцию. В yii2, если вы используете стандартные методы ActiveRecord, вложенные транзакции могут повлиять на ваш код. Попробуйте временно отключить `afterSave` или проверить, вызывается ли он несколько раз.
6. **Логи трассировки и отладка**: Включите более детальные логи для проверки блокировки, чтобы убедиться, что вы понимаете, какие операции выполняются на уровне базы данных. Используйте команды для просмотра активных транзакций и блокировок, например, `SHOW ENGINE INNODB STATUS`.
7. **Использование `EXECUTE` для избежать проблем с `afterSave`**: Попробуйте выполнить `UPDATE` через `EXECUTE` в контексте одной и той же транзакции, чтобы избежать потенциального взаимодействия с триггерами или состоянием гонки, если такие операции происходят.
Если после всех проверок проблема сохраняется, вы можете рассмотреть использование механизма контроля версий (например, хранить текущую версию записи и проверять её перед обновлением) для явного предотвращения перезаписи данных.
Также, если у вас есть возможность, попробуйте провести анализ и улучшить логику работы стороннего сервиса, который взаимодействует с вашей базой данных, если это возможно.