Web-сервис JAX-WS с транзакциями JPA - PullRequest
0 голосов
/ 04 октября 2018

Я сойду с ума от JPA ...

У меня есть такой веб-сервис JAX-WS

@WebService
public class MyService
{
    @EJB private MyDbService myDbService;

    ...
    System.out.println(dmrService.read());
    ...
}

Мой EJB содержит

@Stateless
public class MyDbService
{
    @PersistenceContext(unitName="mypu")
    private EntityManager entityManager;

    public MyEntity read()
    {
    MyEntity myEntity;

    String queryString = "SELECT ... WHERE e.name = :type";

    TypedQuery<MyEntity> query = entityManager.createQuery(queryString,MyEntity.class);
    query.setParameter("type","xyz");

    try
    {
        myEntity= query.getSingleResult();
    }
    catch (Exception e)
    {
        myEntity= null;
    }

    return myEntity;
}

В моем persistence.xml у mypu есть transaction-type="JTA" и jta-data-source

Если я позвоню в веб-службу, она работает.Сущность извлекается из базы данных.

Теперь, используя внешний инструмент, я изменяю значение одного поля в своей записи.

Я снова вызываю веб-службу и ... Отображаемая сущность содержит старое значение.

Если я снова развертываю или добавляю entityManager.refresh (myEntity) после запроса, у меня снова хорошее значение.

Ответы [ 2 ]

0 голосов
/ 05 октября 2018

В @MyTwoCents answer вариант 2 - НЕ использовать свой «внешний» инструмент для изменений, используйте вместо этого свое приложение.Кэширование более полезно, если ваше приложение знает обо всех происходящих изменениях или каким-то образом информируется о них.Это лучший вариант, но только если ваше приложение может быть единственной точкой доступа к данным.

Принудительное обновление через EntityManager.refresh () или через подсказки для конкретного поставщика onконкретные запросы или путем аннулирования кэша, как описано здесь https://wiki.eclipse.org/EclipseLink/Examples/JPA/Caching#How_to_refresh_the_cache - это еще один вариант.Это заставляет JPA проходить мимо кэша и обращаться к базе данных по конкретному запросу.Проблемы с этим заключаются в том, что вы должны либо знать, когда кэш устарел и нуждается в обновлении, либо поставить его на запросы, которые не переносят устаревшие данные.Если это происходит довольно часто или при каждом запросе, то ваше приложение выполняет всю работу по поддержанию неиспользуемого кэша.

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

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

0 голосов
/ 04 октября 2018

Не сердитесь, все в порядке

Поток идет следующим образом.

  • Вы запустили запрос, говорящий, где type = "xyz"
  • Теперь Hibernate сохраняетэтот запрос или состояние в кеше, так что если вы запустите запрос снова, он вернет то же значение, если состояние не изменится.
  • Теперь вы обновляете детали из какого-то внешнего ресурса.
  • Hibernate не имеет каких-либоподсказка об этом
  • Так что при повторном запуске запроса он возвращается из catch
  • Когда вы обновляете, hibernate получает подробности из базы данных

Решение:

  1. Таким образом, вы можете добавить обновление перед вызовом get call

ИЛИ

Измените значение таблицы с помощью методов Hibernate в приложении, чтобы Hibernate знал об изменениях.

ИЛИ

Отключение кэша Hibernate для запросов каждый раз из БД (не рекомендуется, поскольку это замедляет работу)
...