4

我的 EJB3.1 bean 初始化遇到了困难,更具体地说,由于感知到的事务回滚而导致它失败,即使我已经用@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因此,在客户端调用down to#init和在这些层之一内部引发异常之间存在大量堆栈间接级别。它是在 WLS Singleton 会话 bean 管理代码中提出的。见下文...

堆栈类似于下面的(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 组件来编译此 bean,但我们在服务器(或课程)上使用 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 方法不参与任何提供的事务,或者更具体地说,不试图将事务标记为回滚?- 如果我明确告诉它不要“支持”(关心)任何交易,为什么它会因为这个错误而无法初始化?

注意我已经检查了这个@Singleton bean 未能初始化,因为不是预期的事务状态 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(我需要确认这一点,因为我的线索是通过交易案例来确定的)。如果/何时会报告,但似乎我们在此处尝试回滚不存在的事务时可能会失败。

4

1 回答 1

3

注意这最初不是一个答案,而只是一些更有用的信息,用于挖掘此类问题的答案,因为该领域的在线信息并不多。经过一番努力,终于找到了原因和答案。答案保留在其原始格式中,新发现记录为编辑和调试帮助保持原样,以希望简化其他有类似问题的调试。这是一个黑暗的地方。

好吧,对于上述问题仍然没有明确的答案,问题似乎已经消失了。

我发现(查看不同的NoSuchEJBException问题)WLS 堆栈吞噬了根本原因。

这是开始寻找 SingletonBean failed to init NosuchEJBException 问题的明智之处,以防您没有将其纳入您的PostConstruct方法(即无法创建您的 bean):

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

最初,根异常被捕获并包含NoSuchEJBException在较低级别引发的 s 中,如上所述。但是,在下面的堆栈中,NoSuchEJBException被替换为InternalError被包裹并且原因丢失了。奇怪的是,它甚至可能将自己设置为原因(调试器有点混乱):

SingletonSessionManager#getBeanFor

因此,这是查找根本异常可能是什么的主要场所。

仅供参考:我在第二个实例中的问题是 WLS(spring-repackaged)中的弹簧注入问题,其中数据源没有正确注入我的 ELB 服务 impl,因为@Resource(name="...")JNDI 名称不存在数据源。由于前面提到的异常处理问题,这根本没有记录。一旦我通过并找到原因,这很容易解决。很遗憾不得不花这么多时间来发现它。

[编辑]仅供参考:似乎我的问题导致“InternalException Transaction Rolled-back status 4”异常可能是由于 EJB 初始化(PostConstruct)超过了事务超时。@TransactionAttribute(NOT-SUPPORTED)如果我的 EJB 设置为但显然不是,这应该是无关紧要的。调试显示,对于这个 and @TransactionAttribute(NEVER),有一个invokeTxused at the levelSingletonSessionManager#constructAndInitBean和 managed in the InvocationWrapper. 因此,超时将导致回滚,导致InternalException,映射到NoSuchEJBException,被另一个吞下,NoSuchEJBException导致垃圾错误消息。

[EDIT2]仅供参考:这似乎是由于 WLS 中的一个错误,其中在不应该为@TransactionAttribute(NOT-SUPPORTED). 我们已经向 Oracle 提出了一个错误,该错误给了它 2 级严重程度。与此同时,我们已经将潜在的耗时(网络相关)代码移出该@PostConstruct方法作为一种解决方法。

[EDIT3]仅供参考:来自 Oracle ...类级别事务属性注释未在单例生命周期拦截器 postconstrcut/predestroy 上强制执行,因此它默认为 REQUIRED。

他们同意这是一个问题,并正在研究它。同时,确保您的@PostConstruct. 这将包括基于延迟的超时(我们的问题是间歇性的,因为它取决于访问的地理“服务器”)。

调试提示

作为调试过程,顺便说一句,我想我会:

  1. 在您的 EJB init ( ) 方法中放置一个断点@PostConstruct并展开,直到您在调试值中看到异常发生。
  2. 如果您没有命中 init,请将断点放置在尽可能靠近#doActualInit上面列出的 WLS 的位置,并找到进入 init 方法的方法。然后,只需注意第一次引发异常的时间。请注意,您可能必须将断点放在里面InvocationHandler#invoke才能通过代理层接近它(或滚动您自己的)。
  3. init如果你确实命中了它,请通过在你的和展开或在EjbComponentCreatorImpl.invokePostConstruct(Object, String)和观察中放置一个断点来观察展开的堆栈。
于 2013-07-03T12:06:47.917 回答