Spring TaskExecutor 事务丢失(代理与直接调用) [英] Spring TaskExecutor Transaction Lost (Proxy vs. Direct call)

查看:194
本文介绍了Spring TaskExecutor 事务丢失(代理与直接调用)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试让 TaskExecutor (ThreadPoolTask​​Executor) 为当前运行良好的事务服务工作,但是当我启动任务时,不再找到现有的事务.

I try to get the TaskExecutor (ThreadPoolTaskExecutor) to work for a currently well working service with Transactions but when i start the Task the existing Transaction is not found anymore.

(当下面的 start() 方法被调用时,已经有一个事务处于活动状态)(SimplePOJO 脱离上下文,只保存一些数据,可以说是存储在数据库中)

(When below start() Method is called there is already a transaction active) (The SimplePOJO ist out of context and just holds some data lets say to be stored in the DB)

@Component
@Transactional(rollbackFor = { Exception.class })
public class MyService {

    @Autowired
    MyTaskRunner myTaskRunner;

    public void start() {

        // TransactionSynchronizationManager.isActualTransactionActive() -> true

        SimplePOJO pojo = new SimplePOJO();
        myTaskRunner.executeTask(pojo);
    }
}

Above Service 使用这个组件:

Above Service uses this Component:

@Component
public class MyTaskRunner implements ApplicationContextAware {

    @Autowired
    private TaskExecutor taskExecutor;

    private static ApplicationContext applicationContext = null;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        MyTaskRunner.applicationContext = applicationContext;
    }

    public void executeTask(SimplePOJO simplePOJO) {

        // TransactionSynchronizationManager.isActualTransactionActive() -> true

        MyDelegate myDelegate = applicationContext.getBean(MyDelegate.class);
        myDelegate.setSimplePOJO(simplePOJO);
        taskExecutor.execute(myDelegate);
    }
}

以这种方式配置 ThreadPoolTask​​Executor:

That gets a ThreadPoolTaskExecutor configured this way:

<bean id="taskExecutor"
    class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <property name="corePoolSize" value="1" />
    <property name="maxPoolSize" value="5" />
    <property name="queueCapacity" value="25" />
</bean>

并且应该最终在每个任务的新事务中开始异步工作:

And should finally start the Async work in a new transaction per task:

@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class MyDelegate implements Runnable {

    private SimplePOJO simplePOJO;

    @Override
    public void run() {

        // TransactionSynchronizationManager.isActualTransactionActive()); -> False!

        if (this.simplePOJO != null) {
            this.doStuff(angebotAnfrageContainer);
        }
    }

    public void setSimplePOJO(SimplePOJO simplePOJO) {
        this.simplePOJO = simplePOJO;
    }

    @Async
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    private void doStuff() {

        // TransactionSynchronizationManager.isActualTransactionActive()); -> False!

        // do stuff with the pojos data in the transaction (persist on DB)
    }

}

你对我在这里遗漏的东西有什么建议吗?

Do you have any suggestions what i am missing here?

非常感谢!

我尝试了什么写上面的代码 &在网上搜索了几个小时,这是我发现的:

What i tried Wrote above code & searched the web for hours, this is what i found out:

我必须承认,我对 Spring 非常陌生,还不太了解这个框架.在尝试和搜索网络的最后几个小时内,我认为这与从 spring 创建的代理有关,并且当我调用 execute()-Method 或 TaskRunner 调用 run()-Method 时,该链中断了调用代理直接调用实现(MyDelegate)...但我完全不知道如何验证或更改它.

I have to admit i am very new to Spring and havent yet understood the framework too well. Within the last few hours of trying and searching the web i think it has something to do with Proxys beeing created from spring and that chain breaks when i call the execute()-Method or when the TaskRunner calls the run()-Method that instead of calling the Proxy calls the Implementation (MyDelegate) directly ... but i have absolutly no idear how i could verify or change that.

非常感谢提前

推荐答案

使用 AOP 应用事务.Spring 默认使用 代理 来应用 AOP.代理的使用仅导致对(外部方法调用)对象的调用被拦截.在您的情况下,您正在从对象内部进行方法调用,该方法不会通过代理并且不会被拦截,基本上使您的 @Transactional 无用.

Transactions are applied using AOP. Spring, by default, uses proxies to apply AOP. The usage of proxies result in only calls into (external method calls) the object are intercepted. In your case you are doing a method call from inside the object which will not pass through the proxy and will not be intercepted, basically rendering your @Transactional useless.

简单地将 @Transactional 移动到 run 方法应该可以解决您的问题,因为 run 方法现在将在事务中运行.

Simply moving the @Transactional to the run method should fix your problem as the run method will now run in a transaction.

@Transactional
public void run() {...}

您也可以删除 @Async 因为它在这里没有任何作用,您正在使用 TaskExecutor 执行任务,已经使它们异步(取决于哪个 TaskExecutor 你使用).

You can also remove the @Async as that doesn't do anything here, you are executing task with a TaskExecutor already making them async (depending on which TaskExecutor you use).

链接:

  1. 了解 AOP 代理
  2. TaskExecutor

这篇关于Spring TaskExecutor 事务丢失(代理与直接调用)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆