Google App Engine - не может работать с несколькими группами объектов в одной транзакции - PullRequest
1 голос
/ 24 февраля 2010

Почему я получаю исключение ниже, если тип обоих объектов - PersistentLogin? Я подумал, что это будет означать, что они находятся в одной группе сущностей, но я думаю, что это неверное предположение. Есть идеи как это исправить?

Это код:

// the class is marked with @Transactional
@Override
public final void removeUserTokens(final String username) {
    final Query query = entityManager.createQuery(
        "SELECT p FROM PersistentLogin p WHERE username = :username");
    query.setParameter("username", username);

    for (Object token : query.getResultList()) {
        entityManager.remove(token);
    }
}

Это исключение:

Caused by: javax.persistence.PersistenceException: Illegal argument
    at org.datanucleus.jpa.NucleusJPAHelper.getJPAExceptionForNucleusException(NucleusJPAHelper.java:260)
    at org.datanucleus.jpa.EntityTransactionImpl.commit(EntityTransactionImpl.java:122)
    at org.datanucleus.store.appengine.jpa.DatastoreEntityTransactionImpl.commit(DatastoreEntityTransactionImpl.java:50)
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:467)
    ... 42 more
Caused by: java.lang.IllegalArgumentException: can't operate on multiple entity groups in a single transaction. found both Element {
  type: "PersistentLogin"
  name: "1WfCYx8bmwUGkjzP2PpmFA=="
}
 and Element {
  type: "PersistentLogin"
  name: "SfI0P8RVBjTvu0WHMSuaVA=="
}

Ответы [ 2 ]

5 голосов
/ 24 февраля 2010

Одна и та же группа объектов означает, что объекты имеют общий родительский объект.

Два объекта верхнего уровня никогда не находятся в одной и той же группе объектов.

Есть идеи как это исправить?

Самый простой способ - ослабить требования к транзакции. В вашем случае это означало бы удаление сущностей PersistentLogin по одной (цикл с максимальным усилием, удаляйте как можно больше, повторяйте ошибки, без гарантии атомарности).

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

В нереляционных базах данных вы должны кодировать свое приложение, не полагаясь на транзакции в хранилище данных. Они просто не поддерживают их настолько, насколько мы привыкли.

1 голос
/ 21 февраля 2012

Во-первых, внимательно прочитайте следующие документы, особенно раздел «Использование транзакций между группами» http://code.google.com/appengine/docs/java/datastore/transactions.html

Информация о том, что такое межгрупповая транзакция: http://code.google.com/appengine/docs/java/datastore/overview.html#Cross_Group_Transactions

Примечание. Транзакцию можно выполнить не более чем для 5 различных групп!

Для вашего производственного приложения вы должны включить «High Replication Datastore» в своей панели appengine и включить «транзакции между группами (XG)» в своем исходном коде, jdoconfig.xml или постоянстве. .xml

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

Примечание: если вы запускаете командную строку сервера appengine dev, не забудьте добавить параметр хранилища данных с высокой репликацией:

~/appengine-java-sdk-1.6.2.1/bin/dev_appserver.sh
    --jvm_flag=-Ddatastore.default_high_rep_job_policy_unapplied_job_pct=20
    --address=0.0.0.0 --port=8888 --disable_update_check .

Мы некоторое время боролись с этим при разработке Rogerthat Platform (код работал в рабочей среде и в Eclipse, но не тогда, когда dev_appserver.sh выполняется из командной строки), поэтому мы подумали, что стоит поделиться.

...