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

不同线程上的Quarkus事务

匡玉堂
2023-03-14

我有一个带有异步endpoint的quarkus应用程序,它创建一个具有默认属性的实体,在request方法中启动一个新线程,并执行一个长期运行的作业,然后返回该实体作为响应供客户端跟踪。

@POST
@Transactional
public Response startJob(@NonNull JsonObject request) {
        // create my entity
        JobsRecord job = new JobsRecord();
        // set default properties
        job.setName(request.getString("name"));

        // make persistent
        jobsRepository.persist(job);
        
        // start the long running job on a different thread
        Executor.execute(() -> longRunning(job));

        return Response.accepted().entity(job).build();
    }

此外,长时间运行的作业将在实体运行时对其进行更新,因此它也必须是事务性的。但是,数据库实体没有得到更新。

这些是我面临的问题:

  1. 收到以下警告:
ARJUNA012094: Commit of action id 0:ffffc0a80065:f2db:5ef4e1c7:0 invoked while multiple threads active within it.
ARJUNA012107: CheckedAction::check - atomic action 0:ffffc0a80065:f2db:5ef4e1c7:0 commiting with 2 threads active!

我尝试使用@transaction(value=txtype.requires_new)但没有用。

我尝试在longrunning上使用API方法,而不是在指南中提到的@transactional方法,如下所示:

@Inject UserTransaction transaction;
.
.
.
try {
    transaction.begin();
    jobsRecord.setStatus("Complete");
    jobsRecord.setCompletedOn(new Timestamp(System.currentTimeMillis()));
    transaction.commit();
} catch (Exception e) {
    e.printStackTrace();
    transaction.rollback();
}

但随后出现错误:ARJUNA016051:线程已与事务关联!ARJUNA016079:事务回滚状态为:ActionStatus.Committed

我再次尝试了声明性方法和基于API的方法,这次启用了上下文传播。但还是没有运气。

最后,基于第三种方法,我认为在Http请求处理程序上保留@transactional并保持longrunning不使用声明性或基于API的事务方法是可行的。但是,数据库仍然没有得到更新。

显然,我误解了JTA和上下文传播的工作原理(以及其他方面)。

有没有一种方法(甚至设计模式)可以让我在quarkus web应用程序中异步更新数据库实体?还有,为什么我采取的任何方法都没有效果呢?

使用quarkus 1.4.1.final,ext:[agroal,cdi,flyway,hibernate-orm,hibernate-orm,panache,hibernate-validator,kubernetes-client,mutiny,narayana-jta,rest-client,resteasy,resteasy-jackson,resteasy-mutiny,smallrye-context-propagation,smallrye-health,smallrye-openapi,swagger-ui]

共有1个答案

施敏达
2023-03-14

您应该从您的JAX-RS资源方法返回一个异步类型,然后事务上下文将在异步阶段执行时可用。在quarkus指南中有一些关于上下文传播的相关文档。

首先,我会看一个反应性的例子,比如入门快速入门。尝试用@transactional注释每个资源endpoint,异步代码将与事务上下文一起运行。

 类似资料:
  • 问题内容: 使用JMeter,我要检查仅允许1次更新的锁定部分 我正在运行具有10个线程的线程组,并且期望只有1个(并非总是第一个)线程返回0,而其他9个线程返回1如何断言呢? 线程组(10)-HTTP采样器– 断言 编辑 10实际上是一个动态属性。因此,我需要任何线程计数来期望只有1个断言才能返回成功。 该测试是为了检查记录锁定是否正常工作,即使在压力/负载测试中也只能更新一次记录。 编辑2 使

  • 我正在运行RxJava并创建一个主题以使用方法生成数据。我正在使用Spring。 这是我的设置: 在RxJava流上生成新数据的方式是通过Autowire private SubjectObserver SubjectObserver,然后调用SubjectObserver。发布(newDataObjGenerated) 无论我为subscribeOn()指定了什么 Schedulers.io()

  • 按照本指南,我已将Quarkus应用程序配置为在中找不到文件时返回自定义错误页面。 当我在开发模式下使用Quarkus在本地运行代码时,这非常好。然而,当我构建优步jar时,行为是不同的:当我尝试访问未知路径时,会超时。 为什么我的优步jar表现不同,我该如何解决这个问题?任何帮助都将不胜感激。

  • 我有很多消费者组(每个消费者组一个主题)的用例,因此我必须为一个主题/消费者组创建许多ConcurrentMessageListenerContainer实例。但我希望他们共享一个公共线程池,以控制KafkanConsumer的调用。轮询以及记录的处理方式。您认为这与SpringKafka相关吗,还是我必须实现自己的版本来实例化自己的KafakConsumers?

  • 问题内容: 据我所知,操作系统创建线程时,每个线程都会获得一个不同的堆栈。我想知道每个线程是否也有与自己不同的堆吗? 问题答案: 否。所有线程共享一个公共堆。 每个线程都有一个专用堆栈,它可以快速添加和删除其中的项目。这样可以使基于堆栈的内存速度更快,但是,如果您使用过多的堆栈内存(如无限递归中所发生的那样),则会导致堆栈溢出。 由于所有线程共享同一个堆,因此必须同步对分配器/释放器的访问。有许多