java TransactionAttributeType.NOT_SUPPORTED方法花费挂起事务的事务时间

izj3ouym  于 2023-04-19  发布在  Java
关注(0)|答案(2)|浏览(146)

bounty还有5天到期。回答此问题可获得+50声望奖励。oscar希望引起更多关注此问题。

我有一个方法,它执行繁重的操作(文件处理),不需要事务,但在事务内部并产生超时。我没有重构代码或提高默认事务超时的选项。我尝试在文件处理程序方法中使用TransactionAttributeType.NOT_SUPPORTED来暂时挂起事务,但它在挂起时一直在计算时间并一直给我超时。
这种工作方式是否正确?当交易被暂停时,交易时间是否仍然被花费?
我已经做了下面的例子近似相同的问题。代码:

@Slf4j
@Stateless
public class Foo1 {

    @Inject
    Foo2 foo2;

    @PersistenceContext
    EntityManager em;

    @TransactionTimeout(value= 10, unit = TimeUnit.SECONDS)
    public void saveWith10secondsTimeout() {
        log.info("Start Foo1");
        Foo entity = new entity();
        em.persist(entity);
        foo2.threadSleep15seconds();
        log.info("End Foo1");
    }
}

@Slf4j
@Stateless
@TransactionAttribute(value = TransactionAttributeType.NOT_SUPPORTED)
public class Foo2 {
    public void threadSleep15seconds() {
        log.info("Start Foo2");
        try {
            Thread.sleep(15 * 1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        log.info("End Foo2");
    }
}

控制器调用:

@Inject
Foo1 foo1;

@GET
@Path("/foo-not-supported")
@TransactionAttribute(TransactionAttributeType.NEVER)
public Response testNotSupported() {
    log.info("Start testNotSupported");
    foo1.saveWith10secondsTimeout();
    return Response.status(OK).build();
}

日志:

15:00:30,867 INFO  [com.FooController] (default task-1) Start testNotSupported
15:00:30,868 INFO  [com.Foo1] (default task-1) Start Foo1
15:00:30,883 INFO  [com.Foo2] (default task-1) Start Foo2
15:00:40,867 INFO  [com.arjuna.ats.arjuna] (Transaction Reaper) ARJUNA012117: TransactionReaper::check timeout for TX 0:ffff7f000101:-441cac6:64394e3c:382 in state  RUN
15:00:40,877 INFO  [org.hibernate.resource.transaction.backend.jta.internal.synchronization.SynchronizationCallbackCoordinatorTrackingImpl] (Transaction Reaper Worker 0) HHH000451: Transaction afterCompletion called by a background thread; delaying afterCompletion processing until the original thread can handle it. [status=4]
15:00:40,881 INFO  [com.arjuna.ats.arjuna] (Transaction Reaper Worker 0) ARJUNA012121: TransactionReaper::doCancellations worker Thread[Transaction Reaper Worker 0,5,main] successfully canceled TX 0:ffff7f000101:-441cac6:64394e3c:382
15:00:45,884 INFO  [com.Foo2] (default task-1) End Foo2
15:00:45,884 INFO  [com.Foo1] (default task-1) End Foo1
15:00:45,884 INFO  [com.arjuna.ats.arjuna] (default task-1) ARJUNA012077: Abort called on already aborted atomic action 0:ffff7f000101:-441cac6:64394e3c:382
15:00:45,887 ERROR [org.jboss.as.ejb3.invocation] (default task-1) WFLYEJB0034: EJB Invocation failed on component Foo1 for method public void com.Foo1.saveWith10secondsTimeout(): javax.ejb.EJBTransactionRolledbackException: javax.transaction.RollbackException: WFLYEJB0447: Transaction 'Local transaction (delegate=TransactionImple < ac, BasicAction: 0:ffff7f000101:-441cac6:64394e3c:382 status: ActionStatus.ABORTED >, owner=Local transaction context for provider JBoss JTA transaction provider)' was already rolled back
xjreopfe

xjreopfe1#

事务超时意味着如果事务在时间段过去后仍处于活动状态,则可以回滚该事务。挂起事务对超时没有影响(因为这与设置超时的目的相矛盾)。

pxq42qpu

pxq42qpu2#

这里似乎有一些设计问题。
Foo2.threadSleep15seconds()似乎在模拟您正在谈论的长时间运行的文件进程。文件处理与正在进行的DB事务的关联有多紧密?
如果你可以有某种单独的状态管理,你可以做的是,作为Foo1.saveWith10secondsTimeout()的一部分,你只需要在DB表中插入一条记录,文件处理是pending。并立即返回,这样事务就不会长时间被搁置。
有单独的线程(异步执行Foo2.threadSleep15seconds())来处理所有对Foo1.saveWith10secondsTimeout()发出的请求所要处理的所有文件。(或线程池)将继续处理文件,并根据结果将DB表中这些文件的状态从pending更改为doneerror,然后根据结果。
但是,如果一个事务被延迟到所有文件都被处理完的时候,它肯定会锁定其他地方的一些活动。

相关问题