Согласованное чтение App-Engine JDO не работает, возможно, кеширование?

Сегодня я впервые использую GWT и JDO. Я запускаю его с Eclipse в режиме локальной отладки.

Я делаю следующее:

    public Collection<MyObject> add(MyObject o) {
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
    pm.makePersistent(o);
    Query query = pm.newQuery(MyObject.class);// fetch all objects incl. o. But o only sometimes comes...
List<MyObject> rs = (List<MyObject>) query.execute();
ArrayList<MyObject> list= new ArrayList<MyObject>();
for (MyObject r : rs) {
    list.add(r);
}
return list; 
} finally {
    pm.close();
}
}

Я уже установил <property name="datanucleus.appengine.datastoreReadConsistency" value="STRONG" /> в свой jdoconfig.xml. Должен ли я установить некоторые другие параметры транзакции в конфигурации? Был ли у кого-нибудь рабочий jdoconfig.xml? Или проблема где-то в другом? Какое-то кеширование между ними?

EDIT: Что я пробовал:

  • Установка для NontransactionalRead/Write значения false
  • Использование одного и того же/другого PersistenceManager при многократном вызове PMF.get().getPersistenceManager()
  • Использование транзакций
  • ignoreCache = true на PersistenceManager
  • звоню flush и checkConsistency

jdoconfig:

    <persistence-manager-factory name="transactions-optional">
<property name="datanucleus.appengine.datastoreReadConsistency" value="STRONG" />
    <property name="javax.jdo.PersistenceManagerFactoryClass"
        value="org.datanucleus.store.appengine.jdo.DatastoreJDOPersistenceManagerFactory"/>
    <property name="javax.jdo.option.ConnectionURL" value="appengine"/>
    <property name="javax.jdo.option.NontransactionalRead" value="true"/>
    <property name="javax.jdo.option.NontransactionalWrite" value="true"/>
    <property name="javax.jdo.option.RetainValues" value="true"/>
    <property name="datanucleus.appengine.autoCreateDatastoreTxns" value="true"/>
</persistence-manager-factory>

Должно быть, я упускаю здесь что-то важное, потому что все подходы терпят неудачу...

EDIT2: когда я разделяю задание на две транзакции, в журнале говорится, что транзакция записи выловлена, а затем начинается транзакция чтения. Но он не находит только что сохраненный объект. Он также всегда говорит Level 1 Cache of type "weak" initialised. Неделя плохая или хорошая?

Около 30% запросов идут не так... Может быть, это какая-то проблема с ленивой загрузкой запросов?


person Franz Kafka    schedule 17.12.2011    source источник
comment
Я также сталкиваюсь с той же проблемой. Я добавляю некоторые объекты через свое приложение, но иногда они не отражаются в результатах, а иногда и отражаются!   -  person Vishal Biyani    schedule 18.12.2011
comment
и объект находится в хранилище данных во время выполнения запроса? Очевидно, журнал сказал бы вам об этом. Какое это имеет отношение к GWT непонятно...   -  person DataNucleus    schedule 18.12.2011
comment
Где найти журнал? Какое это имеет отношение к ГВТ? Много, потому что это проект GWT. Я не могу провести четкую грань между GWT и движком приложения, поэтому я называю GWT все, что исходит от Google. И почему кэширование может быть настолько запутанным, что один и тот же экземпляр не может даже прочитать только что записанные данные? Не могли бы вы опубликовать файл jdoconfig.xml, который всегда будет соответствовать одному и тому же клиенту?   -  person Franz Kafka    schedule 19.12.2011
comment
Так много вопросов и так мало документации. Я надеюсь, что вы можете привести меня на правильный путь... Спасибо   -  person Franz Kafka    schedule 19.12.2011
comment
Вы должны удалить это: stackoverflow.com/questions/8563654/   -  person Dave    schedule 19.12.2011
comment
Где найти лог? Конечно же, журнал DataNucleus, поскольку именно его использует плагин Google. Мало документации? Вы имеете в виду спецификацию JDO, документацию проекта DataNucleus, чтобы назвать только два места. Я уже просил вас проверить, действительно ли вы записали данные. И почему я спрашиваю о GWT, так это просто потому, что вы пытаетесь сузить проблему до ограниченных строк кода, а в них ничего GWT нет, поэтому проблема кажется НЕ GWT.   -  person DataNucleus    schedule 20.12.2011


Ответы (3)


Франц, согласованность чтения по умолчанию в конфигурации JDO является СИЛЬНОЙ. так что если вы пытаетесь приблизиться к нему в этом направлении, это вас никуда не приведет

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

http://code.google.com/appengine/articles/transaction_isolation.html

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

РЕДАКТИРОВАТЬ :

Поскольку в упомянутом вами фрагменте кода он запрашивает всю таблицу. И если это то, что вам нужно, вы можете использовать Extent... Способ его использования — вызов

Extent ext = getExtent(<Entity Class name>)

на одноэлементном объекте persistenceManager. Затем вы можете перебирать Extent

Ознакомьтесь с документацией и найдите Экстенты на странице здесь. http://code.google.com/appengine/docs/java/datastore/jdo/queries.html

person Hrishikesh    schedule 20.12.2011
comment
Хорошо, он говорит, что когда фиксация возвращается, не гарантируется, что изменения видны (кто придумал бы такую ​​глупую концепцию?). Теперь вопрос: как я могу заставить видимость? Или я могу сделать некоторые трюки с моим предложением where, потому что вы сказали что-то о запросе всей таблицы? - person Franz Kafka; 20.12.2011
comment
Обновлен комментарий об использовании экстентов. Кроме того, вот объяснение кэширования в JDO. Это может быть полезно. book.javanb.com/using-and-understanding- Java-данные-объекты/ - person Hrishikesh; 20.12.2011
comment
Экстент класса и запрос класса — это одно и то же. - person DataNucleus; 20.12.2011
comment
@Hrishikesh, я считаю, что хотя в документации говорится, что по умолчанию СИЛЬНО, на самом деле это не СИЛЬНО. См. этот вопрос... stackoverflow.com/questions/8112331/ и эта проблема... code.google.com/p/googleappengine/issues/ Это не относится к сути вашего ответа (изоляция транзакций), а является лишь примечанием, о котором стоит упомянуть. - person Dave; 20.12.2011

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

Подробнее о состояниях объектов читайте здесь: http://db.apache.org/jdo/state_transition.html

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

public Collection<MyObject> add(MyObject o) {
    PersistenceManager pm = PMF.get().getPersistenceManager();
    ArrayList<MyObject> list = null;
    try {
        Transaction tx=pm.currentTransaction();
        try {
            tx.begin();
            pm.makePersistent(o);
            tx.commit(); 
        } finally {
            if (tx.isActive()) {
                tx.rollback();
            }
        }

        Query query = pm.newQuery(MyObject.class);
        List<MyObject> rs = (List<MyObject>) query.execute();
        ArrayList<MyObject> list = new ArrayList<MyObject>();
        for (MyObject r : rs) {
            list.add(r);
        }
    } finally {
        pm.close();
    }

    return list; 
}

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

// Note that this only works assuming the makePersistent call is successful
public Collection<MyObject> add(MyObject o) {
    PersistenceManager pm = PMF.get().getPersistenceManager();
    try {
        pm.makePersistent(o);
    } finally {
        pm.close();
    }

    pm = PMF.get().getPersistenceManager();
    ArrayList<MyObject> list = null;
    try {

        Query query = pm.newQuery(MyObject.class);
        List<MyObject> rs = (List<MyObject>) query.execute();
        list= new ArrayList<MyObject>();
        for (MyObject r : rs) {
            list.add(r);
        }

    } finally {
        pm.close();
    }

    return list; 
}

ПРИМЕЧАНИЕ. Изначально я говорил, что перед возвратом можно просто добавить o в список результатов; но это неразумно, поскольку в случае возникновения проблемы с записью o в хранилище данных; тогда возвращенный список не будет отражать фактические данные в хранилище данных. Выполнение того, что у меня сейчас есть (совершение транзакции или закрытие pm, а затем получение другого), должно работать, поскольку для параметра datastoreReadPolicy установлено значение STRONG.

person Dave    schedule 19.12.2011
comment
Я пробовал оба подхода и обертывал чтение и запись двумя разными транзакциями. Иногда это работает, а иногда нет, это серьезно испорчено. Я почистил проект, понизил до jdk6, теперь у меня нет вариантов. Я даже вызываю flush и constancyCheck после коммита, но все это не помогает. Иногда данные просто не попадают в хранилище данных достаточно быстро. Ваша предыдущая идея с добавлением нового объекта в результаты вручную. Я так и сделал, но иногда возникают проблемы с одним запросом позже, потому что этого значения все еще нет в хранилище. Тогда обновление браузера помогает (в основном?). - person Franz Kafka; 20.12.2011
comment
Занимаетесь ли вы каким-либо кэшированием; либо с какой-то Картой, либо через API Memcache? - person Dave; 21.12.2011

Я столкнулся с той же проблемой, и это не помогло. Поскольку это, кажется, лучший результат в Google для «согласованности движка приложения jdo в eclipse», я решил, что поделюсь исправлением для себя!

Оказывается, я использовал несколько экземпляров PersistenceManagerFactory, что привело к странному поведению. Исправление состоит в том, чтобы иметь синглтон, к которому обращается каждый фрагмент кода. На самом деле это правильно задокументировано в GAE. учебники, но я думаю, что его важность занижена.

Получение экземпляра PersistenceManager

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

Поскольку для инициализации экземпляра PersistenceManagerFactory требуется время, приложение должно повторно использовать один экземпляр. Простым способом управления экземпляром PersistenceManagerFactory является создание одноэлементного класса-оболочки со статическим экземпляром следующим образом:

PMF.java

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;

    public final class PMF {
        private static final PersistenceManagerFactory pmfInstance =
            JDOHelper.getPersistenceManagerFactory("transactions-optional");

        private PMF() {}

        public static PersistenceManagerFactory get() {
            return pmfInstance;
        }
    }
person RedSpikeyThing    schedule 03.12.2014
comment
Хотя это решает многие другие проблемы, это не решило проблемы, с которыми столкнулся оригинальный постер (также). Административный интерфейс devserver также неправильно отражает изменения данных. Если я оставлю все, просто посидю некоторое время, иногда я увижу, что вещи сохраняются и становятся доступными. Это кажется случайным, хотя я уверен, что происходит что-то еще. - person BK-; 20.02.2015