Применение уникальных ограничений в GAE - PullRequest
6 голосов
/ 04 октября 2010

Я пробую Google App Engine Java, однако отсутствие уникального ограничения усложняет задачу. Я был через этот пост и этот блог предлагает метод для реализации чего-то подобного. Мой фон находится в MySQL. Перемещение к хранилищу данных без уникального ограничения вызывает у меня беспокойство, потому что мне никогда не приходилось беспокоиться о повторяющихся значениях, прежде чем проверять каждое значение перед вставкой нового значения, все еще есть место для ошибки.

"Нет, вы все еще не можете указать уникальный при создании схемы. "

- Дэвид Андерхилл говорит о GAE и уникальном ограничении ( сообщение )

Что вы, ребята, используете для реализации чего-то похожего на уникальный или первичный ключ?

Я слышал об абстрактном слое хранилища данных, созданном с использованием API низкого уровня, который работал как обычный RDB, который, однако, не был бесплатным (однако я не помню название программного обеспечения)

Схематическое изображение моей проблемы

sNo = biggest serial_number in the db
sNo++
Insert new entry with sNo as serial_number value //checkpoint
User adds data pertaining to current serial_number 
Update entry with data where serial_number is sNo 

Однако в строке № 3 (контрольная точка) я чувствую, что два пользователя могут добавить одно и то же sNo. И это то, что мешает мне работать с appengine.

Ответы [ 4 ]

12 голосов
/ 04 октября 2010

Этот и другие подобные вопросы часто возникают при переходе от традиционного RDB к хранилищу данных, похожему на BigTable, например App Engine.

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

Ответ на ваш вопрос: подумайте, зачем вам это уникальное ограничение.

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

my_user = MyUser(key_name=users.get_current_user().email())
my_user.put()

Это гарантирует, что MyUser никогда не будет создан с этим электронным письмом, и вы также можете быстро получить MyUser с этим электронным письмом:

my_user = MyUser.get(users.get_current_user().email())

Во время выполнения Python вы также можете сделать:

my_user = MyUser.get_or_create(key_name=users.get_current_user().email())

Который будет вставлять или извлекать пользователя с этим электронным письмом.

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

4 голосов
/ 04 октября 2010

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

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

EDIT: Для пояснения, синглтон, который содержит текущий или следующий серийный номер, который должен быть назначен, полностью независим от любых объектов, которым фактически назначены серийные номера. Все они не обязательно должны быть частью группы сущностей. У вас могут быть объекты из нескольких моделей, использующие один и тот же механизм для получения нового уникального серийного номера.

Я недостаточно хорошо помню Java, чтобы предоставить пример кода, и мой пример на Python может быть для вас бессмысленным, но вот псевдокод, чтобы проиллюстрировать идею:

  1. Получить запрос на создание нового предмета инвентаря.
  2. Введите транзакцию.
  3. Получить текущее значение отдельного объекта модели SerialNumber.
  4. Увеличить значение и записать его в базу данных
  5. Возвращаемое значение при выходе из транзакции.

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

Предостережение: как я уже говорил выше, это может быть серьезным узким местом производительности, поскольку в каждый момент времени может быть создан только один серийный номер. Однако он дает вам уверенность в том, что только что созданный вами серийный номер является уникальным и не используется.

3 голосов
/ 20 июня 2011

Я столкнулся с такой же проблемой в приложении, где пользователям нужно было резервировать временной интервал. Мне нужно было «вставить» ровно одну уникальную сущность временного интервала, ожидая, что пользователи одновременно запросят один и тот же временной интервал.

Я выделил пример того, как сделать это на движке приложения, и я написал об этом в блоге . В блоге есть примеры канонического кода с использованием Datastore, а также Objectify. (Кстати, я бы посоветовал избегать JDO.)

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

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

-broc

0 голосов
/ 23 августа 2016

Сначала я подумал, что альтернативой технике транзакций в блоге Broc может быть создание одноэлементного класса, который содержит синхронизированный метод (скажем, addUserName (String name)), ответственный за добавление новой записи, только если она уникальна, или выдачу исключения , Затем создайте contextlistener, который создает один экземпляр этого синглтона, добавляя его в качестве атрибута в servletContext. Затем сервлеты могут вызывать метод addUserName () для экземпляра-одиночки, который они получают через getServletContext.

Однако это НЕ хорошая идея, потому что GAE, вероятно, разделит приложение на несколько JVM, поэтому все еще могут появиться несколько экземпляров одноэлементного класса, по одному в каждой JVM. см. Эту тему

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

<max-instances>1</max-instances>

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

Это модульное решение позволило бы за короткое время добавить в хранилище данных множество уникальных имен пользователей, не рискуя при этом возникать конфликты между группами объектов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...