Мы начинаем разработку нового веб-приложения с использованием JSF (MyFaces на TomEE) и JPA (Eclipselink).
Чтобы ускорить разработку, мы планируем НЕ разрабатывать слой DTO, в основном потому, что он нам не нужен. Следуя советам экспертов JSF и Java EE, таких как Бауке Шольц Как использовать DTO в JSF + Spring + Hibernate и Адам Бьен Насколько злы объекты передачи данных, мы будем использовать объекты JPA непосредственно на уровне представления.
Тем не менее, это приложение должно работать в кластере серверов с липкой сессией. Когда сервер отключается на техническое обслуживание или исключается из кластера для развертывания приложений, пользовательские сеансы этого сервера должны обслуживаться другими серверами без потери сеанса.
Проблема, с которой мы сталкиваемся, заключается в том, что объекты JPA, которые сохраняются в сеансе (например, в bean-компоненте @ViewScoped), не «полностью» реплицируются на других серверах. На самом деле атрибуты коллекции сущностей JPA, которые используют отложенную загрузку, не могут использоваться на других серверах. При доступе к атрибуту коллекции (@OneToMany, использующему отложенную загрузку) на сервере с репликой сеанса исключение
org.eclipse.persistence.exceptions.ValidationException
Exception Description: An attempt was made to traverse a relationship
using indirection that had a null Session.
This often occurs when an entity with an uninstantiated LAZY
relationship is serialized and that relationship is traversed
after serialization.
To avoid this issue, instantiate the LAZY relationship
prior to serialization
брошен.
Я знаю, что EntityManager не сериализуем, и объекты JPA полностью отсоединяются при сериализации во время миграции сеанса, см. Блог Струберга.
Итак, вопрос в том, есть ли способ поддерживать объекты JPA согласованным образом в кластере серверов без использования загрузки EAGER?
Может быть, что-то вроде stackoverflow.com/questions/7058843/… помогает (вопрос о кеше, как в предыдущем комментарии) и использовать его реплицированным способом
Вы пытались проверить, отделена ли сущность + объединена с этой сущностью, прежде чем обращаться к коллекции?
@SorinPenteleiciuc да кеш включен
@tandraschko Да, объекты явно отсоединяются, когда сеансы переносятся на сервер-реплику. Как переподключить их прозрачным образом с точки зрения приложения?
@Kukeltje спасибо, но я думаю, что проблема не связана с кешем. Проблема в том, что сущности на сервере-реплике отсоединены. Так, например, при доступе к коллекциям OneToMany возникает исключение.
Если вы не используете их в сеансе, а повторно используете из кеша, это не проблема iirc. И сущности, помещенные в сеанс, в любом случае отсоединяются от диспетчера сущностей, даже на том же сервере (если вы не используете расширенный контекст сохранения, который сам по себе является «опасным» iirc).
@Kukeltje Я ничего не добавляю в сеанс, это JSF использует сеанс для сохранения области, например ViewScoped. Таким образом, если сервер выходит из строя, пользовательский сеанс перенаправляется на резервный сервер, но все сущности, объявленные на странице ViewScoped, отсоединяются. Я не использую расширенный контекст сохраняемости, доступ к коллекциям через ленивую загрузку в отсоединенных объектах разрешен, см. objectdb.com/issue/326
Я всегда использую EntityManager#merge — такая же проблема возникает, когда вы используете ViewScope с объектами + RequestScoped EM.
Вы можете настроить кеш только для некоторых сущностей (те, которые меняются очень редко)
<?xml version = "1.0" encoding = "UTF-8"?>
<persistence xmlns = "http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version = "2.1">
<persistence-unit name = "name" transaction-type = "JTA">
<!-- disable shared cache because we are in multi instance environment -->
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
<validation-mode>CALLBACK</validation-mode>
<properties>
<!-- disable object caching because we are in multi instance environment -->
<property name = "eclipselink.cache.shared.default" value = "true"/>
<property name = "javax.persistence.sharedCache.mode" value = "ENABLE_SELECTIVE"/>
</properties>
</persistence-unit>
</persistence>
Вы также можете увидеть здесь, как это сделать в общей среде. https://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Caching/Query_Cache
Это не проблема кэша. Если сервер выходит из строя, пользовательский сеанс перенаправляется на резервный сервер, но все сущности, объявленные на странице ViewScoped, отсоединяются. Например, если я получаю доступ к ленивой коллекции @OneToMany на сервере резервного копирования, возникает исключение. Этого не происходит на сервере, который сначала загружается как сущности.
@Alexcat: (Http) Кэш сеанса/отработка отказа! = Кэш jpa/отработка отказа
@Kukeltje да, я знаю. Итак, вы верите, что исключение, о котором я сообщил выше org.eclipse.persistence.exceptions.ValidationException
, связано с кешем jpa? В описании исключения ясно указано, что это происходит, когда сущность сериализуется, и во время миграции (Http)Session объекты сериализуются!
У тебя кеш включен?