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