Как мне справиться с одновременными изменениями в веб-приложении? - PullRequest
7 голосов
/ 29 августа 2011

Вот два возможных рабочих процесса, которые я хотел бы выполнить в веб-приложении.

Вариация 1

  • пользователь отправляет запрос
  • сервер читает данные
  • сервер изменяет данные
  • сервер сохраняет измененные данные

Вариант 2:

  • пользователь отправляет запрос
  • сервер читает данные
  • сервер отправляет данные пользователю
  • пользователь отправляет запрос с изменениями
  • сервер сохраняет измененные данные

В каждом из этих случаев мне интересно: каковы стандартные подходы к обеспечению того, чтобы одновременный доступ к этому сервису приводил к нормальным результатам? (т. е. редактирование никого не происходит, значения соответствуют некоторому порядку редактирования и т. д.)

Ситуация гипотетическая, но вот некоторые подробности того, где мне, вероятно, нужно было бы решать это на практике:

  • веб-приложение, но язык не указан
  • потенциально, используя веб-фреймворк
  • хранилище данных - это реляционная база данных SQL
  • логика слишком сложна, чтобы хорошо выразить ее в запросе, например значение = значение + 1

Я чувствую, что предпочел бы не пытаться изобретать колесо здесь. Конечно, это хорошо известные проблемы с хорошо известными решениями. Пожалуйста, сообщите.

Спасибо.

Ответы [ 3 ]

6 голосов
/ 29 августа 2011

Насколько мне известно, не существует общего решения проблемы.

Корень проблемы в том, что пользователь может долго извлекать данные и смотреть на них на экране, прежде чем делатьобновление и сохранение.

Мне известны три основных подхода:

  1. Когда пользователь читает базу данных, блокирует запись и не выпускает, пока пользователь не сохранитлюбые обновления.На практике это крайне непрактично.Что если пользователь откроет экран, а затем отправится на обед без сохранения?Или уходит домой на день?Или настолько разочарован попыткой обновить эту глупую запись, что он закрывается и никогда не возвращается?

  2. Выражайте ваши обновления как дельты, а не места назначения.Чтобы взять классический пример, предположим, что у вас есть система, которая регистрирует запасы в запасах.Каждый раз, когда происходит продажа, вы должны вычитать 1 (или более) из инвентарного подсчета.

Так, скажем, текущее количество в наличии - 10. Пользователь A создает продажу.Текущее количество = 10. Пользователь B создает продажу.Он также получает текущее количество = 10. Пользователь A вводит, что две единицы проданы.Новое количество = 10 - 2 = 8. Сохранить.Пользователь B вводит одну проданную единицу.Новое количество = 10 (значение, которое он загрузил) - 1 = 9. Сохранить.Ясно, что что-то пошло не так.

Решение: Вместо того, чтобы писать «обновить количество инвентаря = 9, где itemid = 12345», напишите «обновить количество инвентаря = количество-1, где itemid = 12345».Затем дайте базе данных поставить в очередь обновления.Это сильно отличается от стратегии № 1, поскольку база данных должна блокировать запись достаточно долго, чтобы прочитать ее, выполнить обновление и записать ее.Не нужно ждать, пока кто-то смотрит на экран.

Конечно, это можно использовать только для изменений, которые могут быть выражены как дельта.Если, скажем, вы обновляете номер телефона клиента, это не сработает.(Например, старое число 555-1234. Пользователь A говорит, что нужно изменить его на 555-1235. Это изменение +1. Пользователь B говорит, что нужно изменить его на 555-1243. Это изменение +9. Таким образом, общее изменение+10, новый номер клиента - 555-1244. :-)) Но в подобных случаях «последний пользователь, который нажмет клавишу ввода, выиграет», вероятно, лучшее, что вы можете сделать в любом случае.

  1. При обновлении убедитесь, что соответствующие поля в базе данных соответствуют вашему значению «from».Например, скажем, вы работаете в юридической фирме, ведя переговоры по контрактам для ваших клиентов.У вас есть экран, где пользователь может вводить заметки о переговорах.Пользователь А вызывает запись контракта.Пользователь B вызывает ту же запись контракта.Пользователь А вводит, что он только что говорил с другой стороной по телефону, и они согласны с предложенными условиями.Пользователь B, который также пытался позвонить другой стороне, вводит, что они не отвечают на телефонные звонки, и он подозревает, что они обескураживают.Пользователь A нажимает сохранить.Мы хотим, чтобы комментарии пользователя B перезаписывали комментарии пользователя A?Возможно нет.Вместо этого мы отображаем сообщение, указывающее, что примечания были изменены, так как он прочитал запись, и позволяющие ему увидеть новое значение, прежде чем решить, следует ли продолжить сохранение, отменить или ввести что-то другое.

[Примечание: форум автоматически нумерует мои нумерованные списки.Я не уверен, как это переопределить.]

0 голосов
/ 29 августа 2011

Если у вас нет транзакций в MySQL, вы можете использовать команду обновления, чтобы гарантировать, что данные не повреждены.

UPDATE tableA  SET status=2  WHERE status = 1

Если статус один, то только один процесс может получить результат, которыйзапись была обновлена.В приведенном ниже коде возвращается -1, если обновление НЕ было выполнено (если не было строк для обновления).

PreparedStatement query;
query = connection.prepareStatement(s);
int rows = -1;
try
{
    rows = query.executeUpdate();
    query.close();
}
catch (Exception e)
{
   e.printStackTrace();
}
return rows;
0 голосов
/ 29 августа 2011

На уровне приложений все просто - каждый запрос обслуживается другим потоком (или процессом), поэтому, если у вас нет состояния в ваших классах (службах) обработки, все безопасно.

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

Транзакции имеют набор свойств - ACID , что "гарантирует, что транзакции базы данных обрабатываются надежно".*

...