Я работаю над проектом, который находится в процессе перехода от доказательной концепции к чему-то, достойному пилотного проекта. Одним из ключевых улучшений для этого этапа разработки является переход от текущего механизма «сохранения», который использует хеш-таблицу, хранящуюся в памяти и периодически сбрасываемую в файл, в более традиционную базу данных базы данных.Оптимистическая блокировка на стороне сервера в приложении ReSTful: обработка асинхронных запросов от одного и того же клиента
Само приложение разработано с учетом принципов ReSTful. Он использует Джерси для предоставления доступа к ресурсам и jQuery, чтобы предоставить эти ресурсы пользователю и включить базовые взаимодействия (создавать, обновлять, удалять). Довольно прямолинейно.
Я успешно использовал JPA и Hibernate в прошлом для сохранения состояния на стороне сервера в реляционной базе данных, поэтому в этом случае это был естественный выбор. С несколькими незначительными изменениями в объектах модели я смог получить основные операции чтения, создания и удаления, работающие в разумные сроки. Однако операция обновления оказалась более сложной.
Клиентская часть приложения автоматически отправляет изменения на сервер через пару секунд после изменения пользователем ресурса. Кроме того, есть кнопка «сохранить и закрыть», которую пользователь может нажать, чтобы отправить последнюю версию ресурса на сервер, прежде чем вернуться на домашнюю страницу.
Моя первая проблема заключалась в том, как обновить управляемый объект из базы данных неуправляемым объектом, исходящим от клиента. Поскольку данные, отправленные клиенту, преднамеренно пропускают ключи базы данных, это было немного утомительно, поскольку оно сводилось к явно «слиянию» элементов из неуправляемого объекта в объект Hibernate. Это не мой вопрос, но если кто-нибудь знает об изящном способе сделать это, мне было бы очень интересно услышать об этом.
Моя вторая проблема и объект этого сообщения возникает, когда я нажимаю кнопку «Сохранить и закрыть» примерно в то же время, что и операция автоматического сохранения, о которой я упоминал ранее. Чаще всего я получаю оптимистичное исключение блокировки. Это связано с тем, что вторая операция обновления обрабатывается в отдельном потоке, а первая все еще обрабатывается.
Ресурс имеет «обновленную» метку времени, которая устанавливается каждый раз, когда выполняется обновление, поэтому обновление базы данных практически гарантировано каждый раз, даже если ничего не изменилось. Само по себе это, вероятно, проблема, но даже после того, как я ее исправил, все еще есть «окно возможностей», где пользователь может внести изменения и отправить его на сервер, пока выполняется автоматическое сохранение, вызывая ту же проблему ,
Самый простой подход, который я могу решить для решения этой проблемы, состоит в том, чтобы переработать часть Javascript на стороне клиента, чтобы гарантировать, что в любой момент времени у этого клиента есть только одна выдающаяся операция «обновления». (Обратите внимание, что если клиент выполняет обновление одного и того же ресурса одновременно, оптимистичное исключение блокировки отлично.) Однако я обеспокоен тем, что форсирование этого ограничения на клиенте может быть отклонено от духа ReST , Можно ли ожидать, что у данного клиента будет не более одного выдающегося запроса «обновления» (PUT) к определенному ресурсу в любой момент времени в приложении ReSTful?
Это похоже на довольно распространенный сценарий, но я не смог найти окончательного ответа о том, как лучше всего его обрабатывать. Другие идеи, которые я рассмотрел и отбросил, включают в себя как-то сериализацию запросов от одного и того же клиента (возможно, на основе HTTP-сеанса), чтобы они обрабатывались по порядку, внедряя «очередь» обновлений для рабочего потока JPA/Hibernate и вставляя новые " версии "ресурса, отслеживая последний, а не обновляя какую-либо одну запись.
Любые мысли?Ограничение «одного выдающегося обновления за раз» на клиенте кажется разумным или есть лучший подход?
Вы выигрываете по умолчанию, mogsie. Я предполагаю, что это способ использования приложений ReST - на самом деле это не спецификация, выходящая за рамки RFC 2616. Если поведение явно не определено для HTTP 1.1, то это все догадывается, что такое «правильный», способ сделать что-то. Как вы полагаете, для клиента, вероятно, просто «здравый смысл» избежать отправки нескольких запросов PUT, не дожидаясь ответа между ними. Я как бы надеялся на некоторое обсуждение от других, которые столкнулись с одной и той же проблемой, но я думаю, что это не совсем самая захватывающая тема. :) Спасибо что нашли время ответить. –
На самом деле я столкнулся с проблемой. У нас был клиент, который время от времени обновлял фон (условный «GET») ресурсов, и иногда это происходило одновременно с тем, что _same_ клиент сделал «PUT», потому что пользователь нажал «сохранить». Таким образом, мы сделали единственную нормальную вещь, и это должно было ввести мьютекс в клиенте, чтобы все взаимодействие с одним URI было поставлено в очередь. Я не могу вспомнить, имел ли сервер это, но это имеет смысл и там. – mogsie