Вот два потенциальных рабочих процесса, которые я хотел бы выполнить в веб-приложении.
Вариант 1
- пользователь отправляет запрос
- сервер читает данные
- сервер изменяет данные
- сервер сохраняет измененные данные
Вариация 2:
- пользователь отправляет запрос
- сервер читает данные
- сервер отправляет данные пользователю
- пользователь отправляет запрос с изменениями
- сервер сохраняет измененные данные
В каждом из этих случаев мне интересно: каковы стандартные подходы к обеспечению того, чтобы одновременный доступ к этой службе давал нормальные результаты? (т. е. ничья правка затирается, значения соответствуют некоторому порядку правок и т. д.)
Ситуация гипотетическая, но вот некоторые детали того, где мне, вероятно, придется иметь дело с этим на практике:
- веб-приложение, но не указан язык
- потенциально, используя веб-фреймворк
- хранилище данных - это реляционная база данных SQL
- задействованная логика слишком сложна, чтобы ее можно было хорошо выразить в запросе, например значение = значение + 1
Я чувствую, что предпочел бы не пытаться изобретать велосипед здесь. Конечно, это хорошо известные проблемы с хорошо известными решениями. Пожалуйста, порекомендуйте.
Спасибо.
3 ответа
Насколько мне известно, общего решения проблемы нет.
Корень проблемы в том, что пользователь может извлекать данные и долго смотреть на них на экране, прежде чем выполнить обновление и сохранить.
Я знаю три основных подхода:
Когда пользователь читает базу данных, заблокируйте запись и не отпускайте, пока пользователь не сохранит какие-либо обновления. На практике это совершенно непрактично. Что, если пользователь откроет экран, а затем перейдет на обед без сохранения? Или едет домой на день? Или он так расстроен, пытаясь обновить эту дурацкую запись, что уходит и больше не возвращается?
Выражайте свои обновления как дельты, а не как пункты назначения. В качестве классического примера предположим, что у вас есть система, которая учитывает запасы на складе. Каждый раз, когда происходит распродажа, вы должны вычесть 1 (или более) из подсчета запасов.
Предположим, что в наличии имеется 10. Пользователь A совершает продажу. Текущее количество = 10. Пользователь Б создает продажу. Он также получает текущее количество = 10. Пользователь A вводит, что две единицы проданы. Новое количество = 10 - 2 = 8. Сохранить. Пользователь Б вводит одну проданную единицу. Новое количество = 10 (значение, которое он загрузил) - 1 = 9. Сохраните. Ясно, что что-то пошло не так.
Решение: вместо того, чтобы писать «обновить количество набора инвентаря = 9, где itemid = 12345», напишите «обновить количество набора инвентаря = количество-1, где itemid = 12345». Затем позвольте базе данных поставить обновления в очередь. Это сильно отличается от стратегии №1, поскольку базе данных достаточно заблокировать запись только на время, достаточное для ее чтения, обновления и записи. Не нужно ждать, пока кто-то смотрит на экран.
Конечно, это можно использовать только для изменений, которые могут быть выражены как дельта. Если вы, скажем, обновляете номер телефона клиента, это не сработает. (Например, старый номер 555-1234. Пользователь A говорит, что нужно изменить его на 555-1235. Это изменение на +1. Пользователь B говорит, что нужно изменить его на 555-1243. Это изменение на +9. Таким образом, общее изменение +10, новый номер клиента - 555-1244. :-)) Но в подобных случаях «побеждает последний пользователь, щелкнувший клавишу ввода», вероятно, лучшее, что вы можете сделать в любом случае.
- При обновлении убедитесь, что соответствующие поля в базе данных соответствуют значению "от". Например, предположим, что вы работаете в юридической фирме, которая ведет переговоры с клиентами по контрактам. У вас есть экран, на котором пользователь может вводить заметки о переговорах. Пользователь A вызывает запись контракта. Пользователь B открывает ту же запись контракта. Пользователь А заявляет, что он только что разговаривал с другой стороной по телефону, и они согласны с предложенными условиями. Пользователь B, который также пытался дозвониться до другой стороны, заявляет, что они не отвечают на телефонные звонки, и подозревает, что они препятствуют этому. Пользователь A нажимает кнопку "Сохранить". Хотим ли мы, чтобы комментарии пользователя B перезаписывали комментарии пользователя A? Возможно нет. Вместо этого мы отображаем сообщение, указывающее, что примечания были изменены с тех пор, как он прочитал запись, и позволяющее ему увидеть новое значение, прежде чем решить, продолжить ли сохранение, прервать или ввести что-то другое.
[Примечание: форум автоматически меняет нумерацию моих нумерованных списков. Я не знаю, как это изменить.]
Если у вас нет транзакций в 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;
На уровне приложения все просто - каждый запрос обслуживается другим потоком (или процессом), поэтому, если у вас нет состояния в ваших классах обработки (службах), все в безопасности.
Ситуация усложняется, когда вы достигаете базы данных, то есть где хранится состояние. Там вам понадобятся транзакции, чтобы убедиться, что все в порядке.
У транзакций есть набор свойств - ACID, которые «гарантируют, что транзакции базы данных обрабатываются надежно».
Похожие вопросы
Связанные вопросы
Новые вопросы
database
База данных представляет собой организованный сбор данных. Это коллекция схем, таблиц, запросов, отчетов, представлений и других объектов. Данные обычно организованы так, чтобы моделировать аспекты реальности таким образом, чтобы поддерживать процессы, требующие информации. Используйте этот тег, если у вас есть вопросы о разработке базы данных. Если речь идет о конкретной системе управления базами данных (например, MySQL), используйте этот тег.