当前位置: 首页 > 知识库问答 >
问题:

@当标记为TransactionAttribute=not_SUPPORTED时,Singleton bean未能初始化,因为不需要事务状态4

侯涵煦
2023-03-14

我的EJB3.1 bean初始化有困难,更具体地说,由于感知到的事务回滚而失败,即使我已经用@Transaction属性(NOT_SUPPORTED)标记了bean。这应该意味着任何客户端事务都在bean方法条目上暂停,直到退出(当它将被恢复时。这绝对是我想要的事务apprach。

代码和错误的“要点”如下(注意,其中一些是手摇的,以隐藏细节,但都是相关的和有代表性的):

@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 单例会话 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中的事务(即它是非事务的)。我还没有尝试将其放在描述符中(我刚刚想到并将尝试一下)。我也还没有深入研究单例SessionManager$SingletonLifecycleManager.doActualInit的工作原理,但没有太多关于它的在线信息。

这个问题

换句话说,问题是…-我错过了什么,所以我的bean方法不参与任何提供的事务,或者更具体地说,不尝试将事务标记为回滚?-如果我明确告诉它不支持(关心)任何事务,为什么它应该无法初始化此错误?

注意:我已经检查过这个@Singleton bean未能初始化是因为意外的事务状态1问题,但是我的场景与Java EE安全角色权限无关(我不认为!)

谢了。

更新1

好吧,最新的是,删除我的@TransactionAttribute注释似乎让我度过了失败。这很奇怪,因为默认值应该是 TransactionAttributeType#Required 并且确实,我们在堆栈跟踪中有一个额外的层,如果我调试太久,那么我的 bean init 中就会出现事务超时。

查看堆栈跟踪中的以下级别(慢慢nexting out),我看到有一个事务(实际上是两个):

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,它是从上面原始堆栈跟踪中的SingletonCessionManager#constructAndInitBean调用的。(尽管如此,我需要确认这一点,因为我的潜在客户是通过运行事务案例来确定的)。如果/当我们试图回滚不存在的事务时,我们可能会失败。

共有1个答案

马峻
2023-03-14

N、 这不是一个最初的答案,只是一些更有用的信息,可以帮助我们深入了解这些问题的答案,因为这方面的在线信息并不多。经过进一步努力,原因和答案已经找到。答案保留了原来的格式,新的发现被记录为编辑和调试帮助,希望能够帮助其他有类似问题的人进行调试。这是一个黑暗的地方。

嗯,仍然没有明确的答案,上述问题和问题似乎已经消失了。

但是我发现(看另一个< code>NoSuchEJBException问题),潜在的原因被WLS堆栈所掩盖。

如果您没有将SingletonBean初始化到< code>PostConstruct方法中(例如,您的Bean无法创建),这是开始查找singleton bean未能初始化NosuchEJBException问题的合理位置:

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

最初,根异常被捕获并包含在较低级别引发的< code>NoSuchEJBException中,如上所述。但是,在下面堆栈中的这一点上,< code>NoSuchEJBException被替换为< code>InternalError,该错误被包装,原因丢失。奇怪的是,它甚至可能将自己设置为原因(调试器有点失控):

SingletonSessionManager#getBeanFor

因此,这是查找根异常的最佳位置。

仅供参考:我在第二个实例中的问题是 WLS(Spring重新打包)中的Spring注入问题,其中数据源没有正确注入我的 ELB 服务 impl,因为数据源不存在@Resource(name=“...”)JNDI 名称。由于上述异常处理问题,根本没有记录此情况。一旦我踏入并找到原因,它就很容易解决。不得不花这么多时间找出它,真是太可惜了。

[编辑]仅供参考:似乎我引起“InternalExc的Transact Rolled-back状态4”异常的问题可能是由于EJB初始化(PostCon结构体)超过了事务超时。如果我的EJB设置为@TransactionAt的属性(NOT-SUPPORTED),这应该是无关紧要的,但显然不是这样。调试显示,对于这个和@TransactionAt的属性(NEVER),有一个的级别上使用了一个调用Tx,并在中进行了管理。因此,超时会导致回滚,导致InternalExc的,映射到NoSuchEJBExc的,吞并了其他NoSuchEJBExc的导致垃圾错误消息。

[编辑2]仅供参考:这似乎是由于 WLS 中的一个错误,其中在不应该用于 @Transacthtml" target="_blank">ionAttribute(不支持)时设置和管理 invokeTx。我们已经向Oracle提出了一个错误,他们给了它一个sev 2。同时,作为解决方法,我们已将可能耗时(依赖于网络)的代码@PostConstruct 方法中移出。

[编辑3]仅供参考:来自甲骨文...类级事务属性注释不会在单例生命周期拦截器后构造/预销毁上强制执行,因此它默认为 REQUIRED。

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

调试提示

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

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

 类似资料:
  • 我有一个场景,我需要在应用程序启动时加载一个 bean (ReportManager),以便它可以安排报告执行(由 DataStore bean 从数据库轮询)。 在谷歌上搜索后,我发现了@单件、@启动和@依赖的注释,我是这样使用的: 问题是我在部署期间遇到了非常奇怪的异常: 不是真正的异常消息。特别是我也没有收到任何“初始化”日志条目。当我注释掉dataStore.getReports()调用时

  • 在Kotlin中,如果变量在应用程序启动时为,并且在创建后不能再次赋值为,那么有什么方法可以对其进行注释吗? 我不能将field设置为例如,因为它可以在某个时候被置为空,或者,因为它在使用之前被初始化(或者这可能是解决我的情况的正确方法?)。

  • 我使用初始化Spring bean中的类属性。现在我看到这个任务可以通过Java内置的静态和非静态初始化器来完成。如何使用而不能使用初始化器块?

  • 如果我在我的类中创建一个bool,就像一样,它默认为false。 当我在我的方法中创建相同的bool时,我得到一个错误“使用未分配的局部变量检查”。为什么?

  • 下面的示例类无法编译: 此代码的编译错误消息是: 但是,对于包含以下方法的类,Java不会生成任何错误消息: 关于初始化及其要求,为什么Java对最终实例变量和最终局部变量的处理不同?谢谢

  • 我正在使用React-useState创建状态为的对象。在成功调用API后,将更新为数据对象。 我有一个表单可以更改此状态,但我还有一个取消按钮。单击“取消”时,如何将此状态恢复为其初始值(API调用后)? 我应该创建另一个状态变量和存储初始状态在那里,然后更新我的状态基于?