Spring3 @Transactional @Scheduled not database bound?

This is my first attempt at Spring3 @Scheduled, but I found that I could not commit the 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 see that it starts hourly and loads xxx from the database, but the data is not tied to the database.

In spring xml: tx:annotation-driven

 <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 someone 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 that makes the code more difficult to read. I wonder why the TransactionManager is not entered (and does not open) in the previous code snippets?

Thank you so much!

+8
spring dependency-injection scheduling spring-3 transactional
source share
3 answers

You probably understood this or moved on (I hope so), but in the interests of others:

@Transactional tells Spring to wrap your original ServiceImpl bean with a dynamic proxy server that also implements " Service " (Spring is the default proxy interface, not the implementation). This proxy will transparently handle transaction creation and commit / rollback when you call hourly() on the proxy . However, if you call hourly() directly in your implementation (this is what happens above), the proxy is disabled, so there is no transaction.

http://blog.springsource.org/2012/05/23/understanding-proxy-usage-in-spring/

The solution is either

  • Mark the transaction programmatically, as you do in your dirty decision (you do not need annotations in this case).
  • Make sure your @Scheduled method makes its call to dao.update(xxx); through the service interface, and not directly on your implementation (thereby skipping the proxy). Basically you need to move the @Scheduled method to another bean.

I hope this is clear enough!

+17
source share

When you use annotation-based support, it only works with classes created in this context. My bet is that ServiceImpl is not created in the same context as your transaction manager (directly or by annotation scan).

0
source share

I had the same problem, and after I took the time, I realized that after calling dao.update () in some unrelated code that did not check for null, I got an exception, so it just broke the transaction. There was no stackTrace print because it was well handled by spring (some catch block). I spent some time on this. So, just make sure your transaction method is completed to the end. Hope this helps someone.

Yosi lion

0
source share

All Articles