Бину @Singleton не удалось инициализироваться из-за непредвиденного состояния транзакции 4, когда он помечен как TransactionAttribute=NOT_SUPPORTED

У меня возникли проблемы с инициализацией EJB3.1-компонента и, в частности, из-за сбоя в его работе из-за предполагаемого отката транзакции, даже если я пометил EJB-компонент как @TransactionAttribute(NOT_SUPPORTED), Это должно означать, что любая клиентская транзакция приостанавливается на входе в метод bean до выхода (когда она будет возобновлена. Это определенно транзакционная проверка, которую я хочу.

"Суть" кода и ошибки заключаются в следующем (обратите внимание, что некоторые из них ручные, чтобы скрыть детали, но все они актуальны и репрезентативны):

@Singleton(name = "MyClass")
@ConcurrencyManagement(value = BEAN)
@TransactionAttribute(value = NOT_SUPPORTED)
@Local(MyInterface.class)
public class MyClass implements MyInterface {

    @PostConstruct
    public void init() throws MyException {
        try {
            ...
        } catch LowerLevelException e) {
            throw new MyException("problem", e);
        }
    }

    public Object doSomething(...) throws MyException {
        ...
    }
    ...
}

Это вызывает следующую ошибку:

javax.ejb.NoSuchEJBException: Singleton MyClass(Application: my-ear, EJBComponent: my-ejb.jar) failed to initialize.

который, когда я отлаживаю, на самом деле упаковывает следующее исключение:

weblogic.ejb.container.InternalException: Transaction marked rollback or not expected transaction status: 4

Опять же, отладка поднимает некоторые интересные детали:

  1. Во-первых, мой MyClass#init выполняется полностью и успешно без каких-либо проблем / исключений.
  2. #init вызывается по первому звонку на мой #doSomething метод из клиентского кода (как часть пост-конструкции).
  3. Таким образом, существует множество уровней косвенности стека между вызовом клиента к MyClass#doSomething до #init и исключение поднимается внутри одного из этих слоев. Это поднято в коде управления сессионным компонентом WLS. Увидеть ниже...

Стек похож на приведенный ниже (имена MyClass изменены):

MyClass_fefgu8_Impl(MyClass).init() line: 96              
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]        
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57    
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43            
Method.invoke(Object, Object...) line: 601          
Jsr250Metadata.invokeLifecycleMethod(Object, Method, Object[]) line: 393      
InterceptionMetadata(Jsr250Metadata).invokeLifecycleMethods(Object, LifecycleEvent) line: 365          
InterceptionMetadata.invokeLifecycleMethods(Object, LifecycleEvent) line: 403              
EjbComponentCreatorImpl.invokePostConstruct(Object, String) line: 80               
SingletonSessionManager.constructAndInitBean() line: 369         
SingletonSessionManager.access$300(SingletonSessionManager) line: 63            
SingletonSessionManager$SingletonLifecycleManager.doActualInit() line: 798    <== InternalException raised here
SingletonSessionManager$SingletonLifecycleManager.initInternal(boolean) line: 744     
SingletonSessionManager$SingletonLifecycleManager.getBean() line: 648           
SingletonSessionManager.getBeanFor(InvocationWrapper) line: 285      
SingletonSessionManager.preInvoke(InvocationWrapper) line: 147         
SingletonLocalObject(BaseLocalObject).getBeanInstance(InvocationWrapper) line: 146 
SingletonLocalObject(BaseLocalObject).preInvoke(InvocationWrapper, ContextHandler, boolean, boolean) line: 103         
SingletonLocalObject(BaseLocalObject).__WL_preInvoke(InvocationWrapper, ContextHandler) line: 67               
SessionLocalMethodInvoker.invoke(Invokable, BaseLocalObject, InvocationWrapper, Object[], int) line: 20        
MyClass_fefgu8_MyInterfaceImpl.doSomething(String, String, String, String) line: not available

И исключение отката транзакции фактически возникает в стеке:

SingletonSessionManager$SingletonLifecycleManager.doActualInit() line: 798   

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

Я использую этот EJB-компонент для компиляции этого компонента, но мы используем код WLS EJB на сервере (или курс):

<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>javax.ejb</artifactId>
    <version>3.1</version>
    <scope>provided</scope>
</dependency>

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

Я перечитал много об обработке транзакций EJB и не вижу никаких очевидных проблем. Я считаю, что я использую правильный механизм для обработки транзакции в моем bean-компоненте (т.е. он не транзакционный). Я еще не пытался поместить это в дескриптор вместо этого (о котором я только что подумал и попробую). Я также еще не углубился в то, как SingletonSessionManager$SingletonLifecycleManager.doActualInit работает, но там не так много онлайн об этом.

Вопрос

Перефразируя, вопрос в следующем: - Чего мне не хватает, чтобы мои методы bean-компонентов не участвовали ни в одной из предоставленных транзакций или, более конкретно, не пытались пометить транзакцию для отката? - Почему он не может инициализироваться с этой ошибкой, если я прямо сказал ей не "поддерживать" (заботиться о) какие-либо транзакции?

NB. Я проверил, что этот бин @Singleton не удалось инициализировать из-за непредвиденной проблемы статуса транзакции 1, но мой сценарий не связан с разрешениями роли безопасности Java EE (я не думаю!)

Благодарю.

Обновление 1

Ну, последнее, что удаление моего @TransactionAttribute аннотация, кажется, помогает мне преодолеть неудачу. Это странно, так как по умолчанию должно быть TransactionAttributeType#Required, и действительно, у нас есть дополнительный слой в трассировке стека, и если я отлаживаю слишком долго, я получаю тайм-аут транзакции в моем bean init.

Глядя на следующий уровень в трассировке стека (медленно вытесняя), я вижу, что есть транзакция (ну, на самом деле, два):

SingletonSessionManager.constructAndInitBean() line: 377    

wrap            weblogic.ejb.container.internal.InvocationWrapper  (id=15676)   
L   callerTx    weblogic.transaction.internal.ServerTransactionImpl  (id=15681) 
L   invokeTx    weblogic.transaction.internal.ServerTransactionImpl  (id=15683) 

Я проверю, присутствовали ли они в предварительном удалении @TransactionAttribute сценарий, а также попробовать и посмотреть ServerTransactionImpl,

Обновление 2

Последнее обновление на некоторое время... Тем не менее, я думаю, что я проследил проблему в SingletonSessionManager#postCallback который вызывается из SingletonSessionManager#constructAndInitBean в оригинальной трассировке стека выше. (Я должен был подтвердить это, хотя, поскольку мое лидерство определено, пробегая транзакционный случай). Будет сообщать, если / когда, но кажется, что у нас может быть ошибка при попытке откатить нашу несуществующую транзакцию здесь.

1 ответ

Решение

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

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

Я нашел, хотя (глядя на другой NoSuchEJBException проблема), что основная причина проглатывается стеком WLS.

Это разумное место для начала поиска SingletonBean, который не смог инициировать проблемы NosuchEJBException в тех случаях, когда вы не включили его в свой PostConstruct Метод (т.е. ваш бин не может быть создан):

SingletonSessionManager$SingletonLifecycleManager.doActualInit() line: 819   
SingletonSessionManager$SingletonLifecycleManager.initInternal(boolean) line: 744     
SingletonSessionManager$SingletonLifecycleManager.getBean() line: 648           
SingletonSessionManager.getBeanFor(InvocationWrapper) line: 285      

Первоначально корневые исключения обнаруживаются и включаются в NoSuchEJBException подняты на нижних уровнях, как указано выше. Тем не менее, в точке в стеке ниже, NoSuchEJBException заменяется на InternalError это обернуто и причина (ы) потеряна. Любопытно, что он может даже установить себя как причину (отладчик работает немного неэффективно):

SingletonSessionManager#getBeanFor

Таким образом, это отличное место для нахождения корневого исключения.

К сведению: моя проблема во втором случае заключалась в проблеме подпружиненного внедрения в WLS (перепакованная пружина), когда источник данных не был должным образом введен в мою службу ELB, так как источник данных не существовал с @Resource(name="...") Имя JNDI. Это не было зарегистрировано вообще из-за вышеупомянутой проблемы обработки исключений. Как только я вошел и нашел причину, это было легко исправить. Стыдно тратить столько времени на то, чтобы это выяснить.

[РЕДАКТИРОВАТЬ] К вашему сведению: Кажется, моя проблема, вызвавшая исключение "Внутренний статус транзакции откат 4", могла быть вызвана тем, что EJB init (PostConstruct) превысил время ожидания транзакции. Это не имеет значения, если мой EJB установлен как @TransactionAttribute(NOT-SUPPORTED) но, видимо, не так. Отладка показала, что для этого и @TransactionAttribute(NEVER), есть invokeTx используется на уровне SingletonSessionManager#constructAndInitBean и удалось в InvocationWrapper, Таким образом, тайм-аут вызовет откат, что приведет к InternalException, сопоставленный с NoSuchEJBException проглоченный другим NoSuchEJBException приводя к сообщению об ошибке мусора.

[EDIT2] К вашему сведению: это происходит из-за ошибки в WLS, когда invokeTx установлен и управляется, когда это не должно быть @TransactionAttribute(NOT-SUPPORTED), Мы подняли ошибку в Oracle, который дал ему 2 балла. Тем временем мы удалили потенциально трудоемкий (зависящий от сети) код из @PostConstruct метод в качестве обходного пути.

[EDIT3] К вашему сведению: Из Oracle ... Аннотация атрибута транзакции уровня класса не применяется на одноэлементных перехватчиках жизненного цикла postconstrcut/predestroy, поэтому по умолчанию используется значение REQUIRED.

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

Советы по отладке

Кстати, в процессе отладки, я полагаю, я бы:

  1. Поставьте точку останова в вашем EJB init (@PostConstruct) и раскручивайте до тех пор, пока вы не увидите исключение в ваших значениях отладки.
  2. Если вы не нажали кнопку инициализации, установите точки останова как можно ближе к WLS. #doActualInit перечисленные выше и найдите свой путь в методы init. затем просто посмотрите, когда возникнет исключение. Обратите внимание, что вам, возможно, придется поместить свою точку останова внутрь InvocationHandler#invoke чтобы приблизиться к этому через прокси-слои (или сверните свои собственные).
  3. Если вы нажмете на него, посмотрите на стек раскручивания, поставив точку останова в init и разматывать или в EjbComponentCreatorImpl.invokePostConstruct(Object, String) и смотреть.
Другие вопросы по тегам