GAE HDR: Получают ли данные из ключевых слов в результате транзакции XG?

Рассмотрим второй пример в разделе "Использование для транзакций" ( "обновить объект с помощью именованного ключа или создать его, если он еще не существует" ):

https://developers.google.com/appengine/docs/java/datastore/transactions

Теперь рассмотрим этот сценарий. Многопользовательская игра позволяет только один матч между любыми двумя игроками. Чтобы гарантировать, что ключ создается с использованием каждой из клавиш игрока. Этот ключ используется как ключ объекта UniqueMatch.

Итак, чтобы создать совпадение, создается транзакция XG. В рамках этой транзакции:

  • Мы проверяем, нет ли уже объекта UniqueMatch с этим ключом. Если вызов datastore.get() с использованием этого ключа не бросает EntityNotFoundException, мы знаем, что совпадение между этими двумя игроками уже существует, поэтому мы откатываем() и показываем сообщение об ошибке игрокам.

  • Мы помещаем() все сущности, которые нам нужно создать, чтобы создать совпадение. Это включает в себя объект UniqueMatch, а также несколько других объектов.

  • Затем транзакция завершается.

Кажется, это работает нормально. Тем не менее, я заметил, что могу создать два матча между любыми двумя игроками за короткое время. В течение небольшого периода времени (до 10-20 с в одном из тестов, на самом деле) мои вызовы datastore.get(key) бросают EntityNotFoundException, хотя этот ключ уже был помещен().

Это, по-видимому, конечная последовательность. Но не являются ли репликации сущностей по ключевым гарантированно строго согласованными? На эту гарантию влияет тот факт, что это делается в рамках транзакции XG?

Спасибо заранее,

Ответ 1

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

Из docs (в изоляции и согласованности):

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

Кроме того, за пределами транзакции вы увидите только те блоки, которые были зафиксированы (docs):

Объекты, полученные из хранилища данных по запросам или получателям, будут видеть только зафиксированные данные.

Возможное решение:

Создайте объект UniqueMatch за пределами транзакции (appengine не позволит вам помещать объект с тем же ключом, поэтому он будет генерировать исключение, если объект с тем же ключом уже существует). Затем вы можете создать/поместить другие объекты, необходимые для создания соответствия внутри транзакции (при необходимости).

Наконец, убедитесь, что при создании ключа для UniqueMatch они всегда создаются с помощью игроков в том же порядке, что key(playerA,playerB)!=key(playerB,playerA)