@Singleton bean因为标记为TransactionAttribute = NOT_SUPPORTED而没有预期的事务状态4而无法初始化

时间:2013-06-14 16:16:37

标签: java-ee transactions ejb-3.1 weblogic12c postconstruct

我的EJB3.1 bean初始化有困难,更具体地说,由于感知事务回滚而导致失败,即使我用@TransactionAttribute(NOT_SUPPORTED)标记了bean。这应该意味着任何客户端事务在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 Singleton会话bean管理代码中引发的。见下文......
  4. 堆栈类似于下面的内容(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
    

    事务回滚异常实际上是在stack-frame中引发的:

    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方法不参与任何提供的事务,或者更具体地说,没有尝试标记事务以进行回滚?   - 如果我明确告诉它不要“支持”(关心)任何交易,为什么不能用这个错误初始化呢?

    N.B。我已经检查了这个@Singleton bean failed to initialize because of not expected transaction status 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调用。 (我需要确认这一点,因为我的主要是通过贯穿交易案例确定的)。将报告if / when但似乎我们可能在尝试回滚我们不存在的事务时失败。

1 个答案:

答案 0 :(得分:2)

N.B。这本来不是一个答案,而只是一些更有用的信息,在挖掘中找到这些问题的答案,因为这个领域真的没有太多的在线。经过一些额外的努力,之后发现了原因和答案。答案保留了原始格式,新的发现记录为编辑和调试帮助,以便有希望简化其他类似问题的调试。这是一个黑暗的地方。

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

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

这是开始寻找SingletonBean的合理地方,如果你没有进入你的PostConstruct方法(即你的bean无法创建),则无法初始化NosuchEJBException问题:

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(spring-repackaged)中的弹簧注入问题,其中数据源没有被正确地注入到我的ELB服务impl中,因为数据源不存在{{1 JNDI名称。由于上述异常处理问题,根本没有记录。一旦我介入并找到了原因,这很容易解决。羞耻得花这么多时间找出来。

[编辑] 仅供参考:我的问题似乎导致“InternalException Transaction Rolled-back status 4”异常可能是由于EJB init(PostConstruct)超过了事务超时。如果我的EJB设置为@Resource(name="...")但显然不是这样,那么这应该是无关紧要的。调试显示,对于此@TransactionAttribute(NOT-SUPPORTED),在@TransactionAttribute(NEVER)级别使用invokeTx并在SingletonSessionManager#constructAndInitBean内进行管理。因此,超时会导致回滚,导致InvocationWrapper映射到InternalException,被另一个NoSuchEJBException吞噬,导致垃圾错误消息。

[EDIT2] 仅供参考:这似乎是由于WLS中的一个错误,当不应该为NoSuchEJBException设置和管理invokeTx时。我们已经向Oracle提出了一个错误,它给了它一个sev 2.同时,我们已经将@TransactionAttribute(NOT-SUPPORTED)方法中潜在的耗时(依赖于网络的)代码作为一种解决方法。

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

他们一致认为这是一个问题,正在研究它。在此期间,请确保@PostConstruct内的代码不会违反交易超时。这将包括基于延迟的超时(我们的问题是间歇性的,因为它取决于访问了哪个地理“服务器”)。

调试提示

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

  1. 在EJB init(@PostConstruct)方法中放置一个断点并展开,直到您看到调试值中出现异常为止。
  2. 如果您没有点击初始化,请将断点尽可能接近上面列出的WLS @PostConstruct,并找到进入init方法的方法。然后,只需注意何时首次引发异常。请注意,您可能必须将断点放在#doActualInit内以通过代理层接近(或滚动您自己的断点)。
  3. 如果你确实击中它,请通过在InvocationHandler#invoke中放置断点并展开或init并观察来观察展开堆栈。