2016-10-12 1 views
0

У меня есть приложение Java EE с JPA, реализованное с использованием Eclipselink. Я внедрил базовую систему входа пользователя, используя карту сеанса ExternalContext. Однако кажется, что часто сеанс становится несовместимым с базой данных.JPA Entity не синхронизируется с базой данных с использованием нескольких сеансов

Основной процесс 1. Пользователь A Создает объект BidOrder. 2. Пользователь B создает объект AskOrder. 3. Монитор проверяет два порядка совпадают, и если да создает объект 4. портфель заказов Изменения применяются ко всем пользователям (с помощью Primefaces 5.3 Push)

Когда я просматриваю цены, которые я использую этот метод в моей SessionScoped поддержке боб для моего главного вида:

public void findLatestPrices() 
{ 
    logger.log(Level.INFO, "findLatestPrices with user {0} ",user.getUserId()); 

    findAllOrderBooks(); 
    latestPricesId = new ArrayList<String>(); 
    setLatestPricesResults(request.findLatestPrices()); 
    for (Iterator<OrderBook> it = orderBookResults.iterator(); it.hasNext();) 
    { 
     OrderBook orderBook = it.next(); 
     logger.log(Level.INFO, "Found {0} orderbook price", orderBook.getPrice()); 
    } 

    logger.log(Level.INFO, "End of findLatestPrices with user {0} ",user.getUserId()); 
} 

Это вызывает мое RequestScoped Stateful EJB:

public List<OrderBook> findLatestPrices() { 
     List<OrderBook> orderBooks; 
     List<OrderBook> orderBooksFiltered; 

     Map<Member, OrderBook> map = new LinkedHashMap<Member, OrderBook>(); 

     try { 
      orderBooks = em.createNamedQuery(
        "findAllOrderBooks").setHint("javax.persistence.cache.storeMode", "REFRESH") 
        .getResultList(); 
      for (Iterator<OrderBook> it = orderBooks.iterator(); it.hasNext();) { 
       OrderBook orderBook = it.next(); 
       Member member = orderBook.getBidOrderId().getMember(); 
       map.put(member, orderBook); 

        logger.log(Level.INFO, "findLatestPrices orderbook price : {0}", 
          orderBook.getPrice()); 
        logger.log(Level.INFO, "findLatestPrices orderbook bidorder member : {0}", 
          orderBook.getBidOrderId().getMember().getMemberId()); 
        logger.log(Level.INFO, "findLatestPrices orderbook lastupdate : {0}", 
          orderBook.getLastUpdate()); 
      } 
...} 

Я создаю EntityManager в вышеприведенном боба следующим образом:

@PersistenceContext 
private EntityManager em; 

Из протоколирования я могу видеть, что сессии вернуть данные, которые синхронизированы с базой данных, то есть единичные результаты, когда я планирующие два и т.д. Как вы можете видеть, что я пытался setHint для обновления кэша. Я также пробовал @Cacheable (false) на моем экземпляре OrderBook и @Cache (refreshAlways = true), но безрезультатно.

Я отправляю событие push в @PostPersist созданного объекта (OrderBook). Javascript обработчик событий в моей странице Xhtml затем вызывает следующий remotecommand:

<p:remoteCommand name="updateWidget" 
      autoRun="false" 
      actionListener="#{parliamentManager.findLatestPrices}" 
      update="resultDisplay" 
      onstart="onStart()" 
      oncomplete="onComplete()" 
      onsuccess="onSuccess()" 
      onerror="onError()"> 
      <f:actionListener binding="#{parliamentManager.findTraders()}" /> 
      <f:actionListener binding="# {parliamentManager.findPortfolios()}" /> 
      </p:remoteCommand> 

кажется, что часто результаты findLatestPrices не включают в себя последние объекты для всех портфеля заказов сессий. Возможно ли, что сущность не сохраняется сразу при вызове @PostPersist, работая над теорией о том, что push отправляется на некоторые сеансы до того, как объект полностью сохраняется и отражается JPA?

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

Спасибо, Zobbo

+0

Вы пытались очистить кеш перед выполнением запроса 'em.getEntityManagerFactory(). GetCache(). EvictAll()' – simdevmon

+0

Спасибо за ответ simdevmon. Я пробовал это, но это не имело никакого значения, к сожалению. – zobbo

ответ

1

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

Вы не указали или не указали, как вы получаете EntityManager, или как долго он проживает, но есть два уровня кеширования. Первый - это сам EntityManager, который используется для отслеживания изменений для управления объектами и поддержания их личности. JPA разрешает, но не предусматривает второй уровень кэширования, который используется на уровне EntityManagerFactory. Этот второй уровень кэша - это то, к чему нацелен javax.persistence.cache.storeMode, - он контролирует, что происходит, когда сущности извлекаются из общего кэша. Если сущности уже загружены в кеш первого уровня, поскольку это предназначено для представления транзакционной области, они возвращаются как есть, сохраняя любые несинхронизированные изменения, которые могут быть сделаны приложением, и поставщик JPA должен отслеживать.

Единственный способ, с помощью которого JPA принудительно обновлять управляемую сущность, вызывает вызов em.refresh(), хотя это также может быть выполнено путем вызова em.clear, а затем повторного чтения объекта с использованием javax.persistence. cache.storeMode Обновить подсказку.EclipseLink также имеет подсказку запроса «eclipselink.refresh», которая может использоваться для принудительного обновления запроса экземпляра управляемого объекта.

+0

Привет Крис, спасибо за ответ. Я просто создаю EntityManager с помощью @PersistenceContext, я отредактировал свой пост, чтобы проиллюстрировать. – zobbo

+0

Я пробовал приведенное выше предложение (очистка кеша, а затем с помощью подсказки обновления), но это не сработало. Я не могу называть refresh, так как я возвращаю список сущностей, и проблема в том, что в списке отсутствуют объекты. Поскольку предложение evictall от simdevmon не работает, я начинаю задаваться вопросом, действительно ли это кеш, а не какая-то логическая проблема. – zobbo

+0

Проверьте, что находится в базе данных напрямую, поскольку JPA не может прочитать, чего там нет. – Chris

Смежные вопросы