Spring TaskExecutor 事务丢失(代理与直接调用) [英] Spring TaskExecutor Transaction Lost (Proxy vs. Direct call)
问题描述
我尝试让 TaskExecutor (ThreadPoolTaskExecutor) 为当前运行良好的事务服务工作,但是当我启动任务时,不再找到现有的事务.
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);
}
}
以这种方式配置 ThreadPoolTaskExecutor:
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).
链接:
这篇关于Spring TaskExecutor 事务丢失(代理与直接调用)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!