jakarta-ee - @Singleton bean 在标记为 TransactionAttribute=NOT_SUPPORTED 时无法初始化,因为不是预期的事务状态 4

标签 jakarta-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

同样,调试提出了一些有趣的细节:
  • 首先,我的MyClass#init正在完全成功地执行,没有任何问题/异常。
  • #init第一次调用我的#doSomething来自客户端代码的方法(作为构建后的一部分)。
  • 因此,在客户端调用 MyClass#doSomething 之间存在大量堆栈间接级别。下至 #init并且在这些层之一内部引发异常。它是在 WLS Singleton session 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,但我们在服务器(或类(class))上使用 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 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#postCallbackSingletonSessionManager#constructAndInitBean 调用在上面的原始堆栈跟踪中。 (我需要确认这一点,因为我的线索是通过交易案例来确定的)。如果/何时会报告,但似乎我们在此处尝试回滚不存在的事务时可能会失败。

    最佳答案

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

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

    不过,我发现(查看另一个 NoSuchEJBException 问题)根本原因已被 WLS 堆栈吞噬。

    这是开始寻找 SingletonBean failed to init NosuchEJBException 问题的明智之选方法(即无法创建您的 bean):

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

    最初,根异常被捕获并包含在 PostConstruct 中。 s 在较低的水平上升高,如上。但是,在下面的堆栈中,NoSuchEJBException替换为 NoSuchEJBException被包裹起来并且原因丢失了。奇怪的是,它甚至可能将自己设置为原因(调试器有点困惑):
    SingletonSessionManager#getBeanFor
    

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

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

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

    [编辑2] 仅供引用:这似乎是由于 WLS 中的一个错误,其中在不应该用于 NoSuchEJBException 时设置和管理了 invokeTx .我们向 Oracle 提出了一个错误,该错误已给它 2 级严重性。同时,我们已将可能耗时(与网络相关)的代码移出 @TransactionAttribute(NOT-SUPPORTED)。方法作为解决方法。

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

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

    调试提示

    作为调试过程,顺便说一句,我想我会:
  • 在您的 EJB 初始化 ( @PostConstruct ) 方法中放置一个断点并展开,直到您看到调试值中出现异常。
  • 如果您没有命中您的初始化程序,请将断点放置在尽可能靠近 WLS @PostConstruct 的位置。上面列出并找到进入 init 方法的方法。然后,只需注意第一次引发异常的时间。请注意,您可能必须将断点放在 #doActualInit 内。通过代理层接近这个(或滚动你自己的)。
  • 如果你命中了它,通过在你的 InvocationHandler#invoke 中放置一个断点来观察展开堆栈。和展开或在init和观看。
  • 关于jakarta-ee - @Singleton bean 在标记为 TransactionAttribute=NOT_SUPPORTED 时无法初始化,因为不是预期的事务状态 4,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17112959/

    相关文章:

    java-ee-6 - 运行时 EJB 查找的配置

    java - 跨 Hibernate session 和普通 jdbc 的单个事务

    sql - 如何在 ADO.NET 中设置 XACT_ABORT

    java - 一个支持 bean 应该属于多少个 View ?

    java - 在 JSP 中格式化 HTML

    Java Spring : Compatibility for both transactional and non-transactional versions of mongodb

    java - ejb 无状态类是否必须公开?

    java - 基于EJB架构的应用程序的HTTP和UI层面是什么技术?

    servlets - Java EE 中的 session 超时

    java - 将 Web 项目部署到 Glassfish 3.1 时出现错误