Перейти к содержимому
Все статьи
Разработка

Два сотрудника нажали «Сохранить»: как не потерять правки

·27 октября 2026 г.· 6 мин чтения
Сколько будет стоить ваш проект?Рассчитать стоимость

Чтобы два сотрудника не перезаписали правки друг друга, сохраняйте запись условно: вместе с изменением передавайте версию, на основе которой открыли форму. Сервер должен проверить условие в защищённом пути записи. Если данные уже изменились, интерфейс сохраняет введённый текст и предлагает сравнение, а не молча объявляет победителем последнего нажавшего кнопку.

Оба исправления выглядят правильными

Учебная карточка содержит адрес доставки и контактное примечание. Первый сотрудник меняет адрес, второй — примечание. Оба открыли исходное состояние. Если каждый отправляет полную карточку, второй может вернуть старый адрес вместе со своим новым текстом. Человек не намеревался отменять чужую правку, но результат получился именно таким.

Проверка «сотрудник имеет право редактировать» не решает этот конфликт. Оба действительно могут иметь нужные полномочия. Вопрос другой: актуальна ли прочитанная основа изменения? При разработке CRM это нужно принять отдельным сценарием, особенно для длинных форм, которые остаются открытыми во время работы других людей.

Три состояния нужны и серверу, и экрану сравнения

Сохраняйте связь с исходной версией формы. Для разбора нужны прежняя прочитанная запись, локальные предложения сотрудника и актуальные данные сервера. По двум последним снимкам не всегда понятно, что пользователь сознательно изменил, а что просто отправил обратно как часть старой формы.

В условных HTTP-запросах описана защита от потерянного обновления. Один из механизмов — валидатор ETag и условие If-Match. Это вариант протокола, а не обязательное имя поля в любой внутренней системе. ETag не требуется делать последовательным номером или хешем определённого формата.

Учебная последовательность сохранений

Обозначения v-A и v-B в таблице вымышлены и означают разные версии, не готовые значения HTTP-заголовков. Первое принятое изменение делает прочитанную вторым сотрудником основу устаревшей.

ДействиеПрочитанная основаТекущее состояние сервераРешениеЧто остаётся у человекаСледующий шаг
Оба открыли карточкуv-Av-AРедактирование разрешено по правамКаждый работает со своим черновикомСохранить с условием прочитанной основы
Первый сохраняет новый адресv-Av-AПринять и получить v-BПодтверждённый результат первогоПоказать фактически сохранённую карточку
Второй сохраняет примечание и старый адресv-Av-BОтклонить устаревшее условиеНе уничтожать локальное примечаниеПоказать изменившийся адрес и предложенное примечание
Второй сверил различияОснова обновлена после согласованияv-B либо более новаяНовая условная попыткаСогласованное предложениеПри новом конфликте повторить осмысленное сравнение

Условие и запись нельзя разделять окном гонки

Схема «прочитать версию, проверить, затем когда-нибудь сохранить» оставляет возможность другого изменения между действиями. Реализация должна обеспечить проверку и запись подходящим согласованным способом. Не принимайте демонстрацию, где конфликт ловит только клиентская проверка до отправки: данные могут измениться сразу после неё.

В MDN If-Match описано сильное сравнение валидатора; при невыполненном условии возвращается 412 Precondition Failed. Но один заголовок в запросе не подтверждает защиту, если обработчик игнорирует его или проверяет другой ресурс. Конкретную серверную реализацию нужно испытать на конкурентном сценарии.

Что показать после конфликта

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

Не разрешайте проблему скрытой повторной отправкой прежнего тела с новым валидатором. Такой обход формально использует актуальную версию, но всё равно может затереть изменение первого сотрудника. Новая основа имеет смысл только после подготовки нового согласованного предложения. При повторном конфликте процесс должен оставаться понятным.

Если выбран ручной отказ от своих правок, дайте увидеть последствия. Если допускается принудительная замена, определите полномочия и запись решения отдельно. У обычной кнопки повторной попытки не должно быть скрытого значения «перезаписать всё независимо от остальных». Права и актуальность версии проверяются разными условиями.

Почему разные поля не всегда можно слить автоматически

Адрес и примечание в простом примере могут выглядеть независимыми. Но в реальном процессе изменение одного поля влияет на другое: адрес меняет доступные интервалы доставки, а выбранная услуга — допустимую стоимость. Совмещение двух формально разных полей может дать недопустимую комбинацию. Выберите правила слияния по смыслу сущности, не только по совпадению имён.

В документации EF Core разбор конфликта выделен в самостоятельную логику выбора значений. Там же описаны разные способы контроля конкуренции и ограничения длительных транзакций. Для формы, открытой человеком, нельзя механически держать блокировку базы всё время его размышлений как бесплатное универсальное решение.

Проверить все пути записи

Интеграция, импорт или фоновая обработка могут менять ту же карточку. Если только веб-форма поддерживает версию, другой путь способен обойти защиту и сделать её неполной. Для интеграций через API согласуйте обязательность условия и поведение устаревшей команды, не обещая одинаковые заголовки всем сторонним системам.

  1. Создайте учебную карточку и откройте её двумя редакторами. Сохраните их исходные снимки и предложения.
  2. Выполните две конкурирующие попытки, включая изменение разных и одного поля. Сверьте фактическую запись с объявленной политикой.
  3. Проверьте, что отклонённое сохранение не уничтожило локальный текст и не объявило ложный успех.
  4. Измените карточку ещё раз до согласованной повторной попытки. Новый конфликт тоже должен обрабатываться без тихой перезаписи.
  5. Повторите применимые случаи через импорт и другие разрешённые источники записи.
  6. Проверьте отказ от своего черновика и отдельно разрешённые исключения. Каждое решение должно быть осознанным и объяснимым.

Для внутреннего веб-приложения результатом приёмки станет не наличие поля version, а сохранность двух намерений: принятое изменение остаётся на сервере, отклонённое — доступно человеку для решения. После этого можно обсуждать удобное сравнение и частичное слияние, не скрывая конфликт под обычной кнопкой сохранения.

Вопросы и ответы

Что такое оптимистическая блокировка?

Это подход, при котором при сохранении проверяют, не изменилась ли прочитанная основа. Конфликт требует отдельного решения, а не автоматического разрешения последней записи.

Как If-Match и ETag помогают от потерянного обновления?

Клиент передаёт условие, связанное с полученной версией, а сервер применяет изменение только при его выполнении. Важно обеспечить корректную проверку в пути записи и понятный ответ интерфейса на конфликт.

Чем оптимистическая блокировка отличается от пессимистической?

Оптимистический подход выявляет конфликт при попытке изменения, а пессимистический может удерживать блокировку на время операции. Выбор зависит от процесса; длительная пользовательская форма не делает удержание транзакции универсально подходящим вариантом.

Нужна помощь с проектом?

Обсудим задачу и предложим решение — от сайта до SaaS и защиты.

Связаться