This is my 1st time trying Spring3's @Scheduled , but found I cannot commit to DB. This is my code :
@Service
public class ServiceImpl implements Service , Serializable
{
@Inject
private Dao dao;
@Override
@Scheduled(cron="0 0 * * * ?")
@Transactional(rollbackFor=Exception.class)
public void hourly()
{
// get xxx from dao , modify it
dao.update(xxx);
}
}
I think it should work , I can see it starts-up hourly and load xxx from DB , but data is not committed to DB.
There's been tx:annotation-driven
in spring's xml :
<bean id="entityManagerFactoryApp" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="myapp"/>
</bean>
<bean id="transactionManagerApp" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryApp" />
</bean>
<tx:annotation-driven transaction-manager="transactionManagerApp" />
Can somebody tell me what I missed here ?
I have one 'dirty' solution :
@Service
public class ServiceImpl implements Service , Serializable
{
@Inject
private Dao dao;
@Inject
@Qualifier("transactionManagerApp")
private PlatformTransactionManager txMgrApp;
@Override
@Scheduled(cron="0 0 * * * ?")
@Transactional(rollbackFor=Exception.class)
public void hourly()
{
final TransactionTemplate txTemplateApp = new TransactionTemplate(txMgrApp);
txTemplateApp.execute(new TransactionCallbackWithoutResult()
{
@Override
protected void doInTransactionWithoutResult(TransactionStatus status)
{
//get xxx from dao
dao.update(xxx);
}
});
}
}
It works fine here , but it is so redundant , making the code harder to read. I wonder why TransactionManager is not injected (and opened) in the previous code snippets?
Thanks a lot !
You probably have figured this out or moved on (I hope so), but for the benefit of others:
The @Transactional
annotation tells Spring to wrap your original ServiceImpl
bean with a dynamic proxy that also implements 'Service
' (by default Spring proxies the interface, not the implementation). This proxy will transparently handle the creation and commit/rollback of the transaction when you call hourly()
on the proxy. However, if you call hourly()
directly on your implementation (which is what is happening above), the proxy is bypassed, so there is no transaction.
http://blog.springsource.org/2012/05/23/understanding-proxy-usage-in-spring/
The solution is to either
dao.update(xxx);
via the Service interface, not directly on your implementation (thereby going through the proxy). Basically you need to move the @Scheduled
method to another bean.I hope that is clear enough!