Исключение с использованием EntityManager и Glassfish v3 - IllegalStateException: попытка выполнить операцию на закрытом EntityManager - PullRequest
0 голосов
/ 08 ноября 2018

Я работаю в проекте, который использует JavaEE. Я работаю с серверами Glassfish версии 3. У меня часто возникают проблемы (не всегда) в моих одноэлементных EJB, которые используют экземпляр EntityManager. Часто я получаю эту ошибку:

[timestamp] [http-thread-pool-8080(49)] ERROR com.sun.xml.ws.server.sei.TieHandler.serializeResponse Attempting to execute an operation on a closed EntityManager.
java.lang.IllegalStateException: Attempting to execute an operation on a closed EntityManager.
 at org.eclipse.persistence.internal.jpa.EntityManagerImpl.verifyOpen(EntityManagerImpl.java:1662) ~[org.eclipse.persistence.jpa.jar:2.3.4.v20130626-0ab9c4c]
 at org.eclipse.persistence.internal.jpa.EntityManagerImpl.find(EntityManagerImpl.java:643) ~[org.eclipse.persistence.jpa.jar:2.3.4.v20130626-0ab9c4c]
 at org.eclipse.persistence.internal.jpa.EntityManagerImpl.find(EntityManagerImpl.java:532) ~[org.eclipse.persistence.jpa.jar:2.3.4.v20130626-0ab9c4c]
 at com.sun.enterprise.container.common.impl.EntityManagerWrapper.find(EntityManagerWrapper.java:320) ~[container-common.jar:3.1.2.1]

Журнал продолжается, но я только что показал его. Следующей строкой журнала был вызов WebService, развернутого на том же сервере. И когда эта ошибка возникает, она всегда возникает из-за вызова WebService, развернутого на том же сервере , , который выполняет поиск в базе данных, используя метод 'find' из экземпляра entityManager. .

Менеджер сущностей внедряется вне bean-компонента в @PostConstruct аннотируемого класса @WebService, используя строку '(EntityManager) new InitialContext (). Lookup ("java: comp / env / persistence / etc") ;» Это класс, который получает все входящие запросы и решает, какой компонент должен быть вызван на основе запроса.

Сразу после получения запроса этот класс вызывает соответствующий одноэлементный компонент на основе запроса, передавая введенный EntityManager соответствующему компоненту.

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

Я не вижу разумного решения этой проблемы. Все, что я нахожу в онлайн-ресурсах, это то, что может быть ошибкой Glassfish и перезапустить сервер обычно работает. Ничего конкретного для решения проблемы.

Некоторая информация, представленная в PersistenceUnit, настроенном в используемом мной файле persistence.xml, представлена ​​ниже.

<persistence-unit> name="XXX" transaction-type="JTA"
<provider>org.eclipse.persistence.jpa.PersistenceProvider></provider>
<jta-data-source>jdbc/YYY</jta-data-source>
<properties>
            <property name="eclipselink.target-database" value="Oracle"/>
            <property name="eclipselink.cache.shared.default" value="false"/>
            <property name="eclipselink.cache.size.default" value="0"/>
            <property name="eclipselink.cache.type.default" value="None"/>
            <property name="eclipselink.weaving.internal" value="false"/>
            <property name="toplink.target-database" value="Oracle"/>
            <property name="eclipselink.session.customizer"                       
            value="aaa.bbb.ccc.IsolateEmbeddablesCustomizer"/>
 </properties>
 <exclude-unlisted-classes>true</exclude-unlisted-classes>
 </persistence-unit>

Есть ли у вас какие-либо идеи о том, как решить эту проблему, и кто-нибудь из вас тоже получил такую ​​же ошибку?

Спасибо.

1 Ответ

0 голосов
/ 09 ноября 2018

Я думаю, что проблема заключается только здесь:

Менеджер сущностей вводится за пределы компонента в @PostConstruct аннотированного класса @WebService, используя строку «(EntityManager) новый InitialContext () поиск ( "Java: комп / ENV / сохранение / и т.д.");». ...

Контейнер предоставляет EntityManager s из некоторого пула, который он поддерживает. У EM есть некоторый жизненный цикл, и они могут стать недействительными в определенный момент времени. Обычно (объяснено чуть позже) это не будет проблемой, так как обычно EM вводятся управляемым способом.

Но вы инициализируете его один раз в @PostConstruct для некоторой переменной, и когда EM, на которую указывает эта переменная, становится недействительной, она не инициализируется повторно или около того, потому что она не управляется контейнером, как предполагалось.

Я думаю, что вы можете обойти эту проблему, просто проверив, является ли EM недействительным, и снова выполните поиск, если ссылка недействительна. Но Я подчеркиваю: это не правильный путь.

прохождение введенного EntityManager для соответствующего компонента.

Не передавайте EM. Инициализируйте EM в бине, который его использует. Вы не будете иметь сбережений , передав один-единственный экземпляр. Наоборот, это может ухудшить производительность. Пусть контейнер занимается оптимизацией создания EM.

Итак, обычно вы будете делать что-то подобное в своих бобах (не передавая EM, а управляя этим на бобе):

@PersistenceContext(unitName="XXX") // "unitName" might not be needed
private EntityManeger em;           // if you use only one persistence unit

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

Если у вас правильно сконструированы bean-компоненты, которые вы позволяете контейнеру инициализировать, например, @Inject, передавая их в @WebService, это должно быть возможно.

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

...