问题
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.
(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 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);
}
}
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?
Very many thanks in advance!
What i tried Wrote above code & searched the web for hours, this is what i found out:
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.
Very many thanks in advance
回答1:
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.
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() {...}
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).
Links:
- Understanding AOP Proxies
- TaskExecutor
来源:https://stackoverflow.com/questions/23388088/spring-taskexecutor-transaction-lost-proxy-vs-direct-call