Google App Engine: нельзя работать с несколькими группами сущностей в одной транзакции.

Почему я получаю указанное ниже исключение, если тип обоих сущностей — 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=="
}

person Taylor Leese    schedule 24.02.2010    source источник


Ответы (2)


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

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

Любые идеи, как это исправить?

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

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

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

person Thilo    schedule 24.02.2010
comment
У меня проблема в том, что когда я делаю свой метод или класс без @Transactional, я получаю следующее исключение: org.datanucleus.exceptions.NucleusUserException: диспетчер объектов был закрыт - person Taylor Leese; 24.02.2010
comment
См. этот вопрос, который я разместил: stackoverflow.com/questions/2294867/ - person Taylor Leese; 24.02.2010

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

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

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

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

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

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

~/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 (код работал в рабочей среде и в Eclipse, но не когда dev_appserver. sh выполняется из командной строки), поэтому мы подумали, что стоит поделиться.

person Carl D'Halluin    schedule 21.02.2012