0

I have a JSF2 application that is using JPA2/Hibernate with Spring @Transactional. There are no @Transactional statements in the UI (backing beans), only in the service layer. (I am using @Transactional(propagation=Propagation.MANDATORY) in the DAOs to ensure every call occurs in a transaction.) It's all works very nicely, except...

When I am opening and updating the entities through the transactional service methods, Sometimes the retrieved entities are old. It doesn't matter that it's the same user in the same session, occasionally, the JPA "read" methods return older stale entities that have (should have) already been replaced. This stumped me for quite a while, but it turns out it is caused by caching in the Entity Manager. The DAOs are annotated with @Repository, so the injected EntityManager is being reused. I had expected that when the transaction completed, the entity manager would automatically be cleared. But that is not the case. Usually the Entity Manager returns the correct value, but often it reaches back and returns an old one from an earlier transaction instead.

As a workaround, I have sprinkled strategic entityManager.clear() statements in the DAO read methods, but that is ugly. The entityManagers should be cleared after each transaction.

Has anyone experienced this? Is there a proper solution? Can the entity manager be cleared after each transaction?

Thanks very much.

I am using: org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean and org.springframework.orm.jpa.JpaTransactionManager

John
  • 101
  • 1
  • 7

2 Answers2

1

The @Transactional annotation exists in the service layer. The service methods marked with @Transactional will adhere to the ACID properties no matter how many DAO calls are made from within it.

This means that you need not annotate the DAO methods as @Transactional.

I am working on something similar and this is how I have done it and my data is consistent.

Try it this and see if you are still getting inconsistent data.

  • I want to ensure that if one of the DAO methods is ever invoked directly, outside an existing transaction, that an exception is thrown. The DAOs must never start a transaction. I thought that's what the @Transactional(propagation=Propagation.MANDATORY) would do. – John Sep 12 '12 at 11:43
  • The DAOs should never be invoked directly. The service layer accesses the DAO layer. The controller/Endpoint should access the Service layer. So why think about DAOs being invoked directly. The Service layer ll invoke the DAOs. – Arun Padmanabhan Sep 12 '12 at 13:22
  • Also does it behave the same way if only @Transactional is added to the DAO, ie without propagation=Propagation.MANDATORY. – Arun Padmanabhan Sep 12 '12 at 13:36
  • The default propagation is REQUIRED which could cause transactions to be created in the DAO. I don't want to do that. – John Sep 12 '12 at 14:05
0

Do you use @PersistenceContext annotation (above EntityManager in DAO) combined with PersistenceAnnotationBeanPostProcessor bean (you don't have to define PersistenceAnnotationBeanPostProcessor bean if you are using <context:annotation-config/> and <context:component-scan/> XML tags) ? If not, I guess this is the reason of your problems.

Tomasz Szymulewski
  • 2,003
  • 23
  • 23