Quarkus 与 JPA / Hibernate Session 导致 JMS 线程中出现 ContextNotActiveException

问题描述 投票:0回答:1

我尝试从线程使用 Panache 存储库,该存储库不是由 Quarkus “管理”的(因为我们使用 ActiveMQ 5 JmsListeners,其中 javax.jms.MessageConsumer 在其自己的线程池中运行。它的实现如下代码片段:

@ApplicationScoped
public class MyConsumer implements javax.jms.MessageListener {

    @Inject
    javax.jms.ConnectionFactory connectionFactory;
    
    @Inject
    MyPanacheRepository repository;
    
    private Session session;
    
    public void init(@Observes StartupEvent event) {
        if (this.connectionFactory != null) {
            try {
                Connection connection = this.connectionFactory.createConnection();
                connection.start();
                this.session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
                Topic topic = session.createTopic(...);
                MessageConsumer consumer = this.session.createConsumer(...);
                consumer.setMessageListener(this);
            } catch (JMSException e) {
                ...
            }
        }
    }
    
    @PreDestroy
    public void destroy() {
        if (this.session != null) {
            try {
                this.session.close();
            } catch (JMSException e) {
                ...
            }
        }
    }
    
    public void onMessage(Message message) {
        Job job = this.repository.findById(message.getLongProperty("jobId"));
    }

}

当 onMessage() 方法收到消息时,出现以下异常:

ERROR [MyConsumer] (ActiveMQ Session Task-3)  javax.enterprise.context.ContextNotActiveException: Cannot use the EntityManager/Session because neither a transaction nor a CDI request context is active. Consider adding @Transactional to your method to automatically activate a transaction, or @ActivateRequestContext if you have valid reasons not to use transactions.
at io.quarkus.hibernate.orm.runtime.session.TransactionScopedSession.acquireSession(TransactionScopedSession.java:106)
at io.quarkus.hibernate.orm.runtime.session.TransactionScopedSession.find(TransactionScopedSession.java:173)
at org.hibernate.engine.spi.SessionLazyDelegator.find(SessionLazyDelegator.java:650)
at org.hibernate.Session_5b93bee577ae2f8d76647de04cfab36afbf52958_Synthetic_ClientProxy.find(Unknown Source)
at io.quarkus.hibernate.orm.panache.common.runtime.AbstractJpaOperations.findById(AbstractJpaOperations.java:179)
at MyPanacheRepository.findById(MyPanacheRepository.java)

因此 PanacheRepository 找不到获取在线程 ActiveMQ 会话任务 3 中运行的 Hibernate 会话的方法。

解决这个问题的最佳解决方案是什么?我可以通过在 findById(....) 周围添加 UserTransaction.begin() 调用来解决这个问题,但我真的不需要事务来读取数据!?

jpa jms activemq quarkus quarkus-panache
1个回答
0
投票

我希望我早点为你看到这个。

问题是当您尝试打开与数据库的连接时,请求上下文尚未激活,因为应用程序尚未完成启动。

这一行:

public void init(@Observes StartupEvent event) {}

将使您的 init 函数在 Quarkus 应用程序完成其所有启动任务之前运行,其中之一是与数据库建立请求上下文。

为了解决您的问题,您可以在 init 方法上添加此注释,告诉它在运行 init 方法之前启动数据库请求上下文。

import jakarta.enterprise.context.control.ActivateRequestContext;
        
@ApplicationScoped
public class MyConsumer implements javax.jms.MessageListener {
    
    @ActivateRequestContext
    public void init(@Observes StartupEvent event) {}
}
© www.soinside.com 2019 - 2024. All rights reserved.