Raphael Jolivet
Raphael Jolivet

Reputation: 4040

JPA Transactions and REST Services : Good practices

I am writing an application providing REST services (with Apache-CXF) that manage JPA entities (with Hibernate).

I am a bit lost with Transaction management and would like your advice on this topic.

For now, I have put an intermediate layer between my business REST services and the lower services, solely for transaction management purpose.

Currently, my code looks much like that :

@Service 
class PersistanceService<MyBusinessClass>{
   MyBusinessClass load(Long id);
   void save(MyBusinessClass businessObject);
}

@Service 
class BusinessService<MyBusinessClass>{
   void doSomethingOn(MyBusinessClass businessObject);
}

@Service
class TransactionBusinessService<MyBusinessClass>{
   @Transactional
   void doSomethingOn(Long id) {
      MyBusinessClass businessObject = persistanceService.load(id);
      businessService.doSomethingOn(businessObject);
      persistanceService.save(businessObject);
   }
}

@Service
@path("/foo")
class RESTService {
   @Path("/doSomething")
   void doSomethingOn(Long id) {
      transactionBusinessService.doSomethingOn(id);
   }
}

I think the TransactionBusinessService is overkill. I would like ''Spring'' or ''CXF'' to handle transactions for me : I feel that a request is the good granularity to do so : Init an entity manager at the beginning of each request, and commit updates at the end.

I've tried to add the @Transactional annotation to the REST methods themselves, but it seem to be ignored, or to conflict with CXF.

  1. Do you think it is a good idea to delegate the transaction at the request level and not to bother about it anymore ?
  2. How can I have Spring or CXF bind the transaction management to the requests for me ?

Thanks in advance for you advice.

Upvotes: 2

Views: 2842

Answers (1)

n1ckolas
n1ckolas

Reputation: 4440

Do you think it is a good idea to delegate the transaction at the request level and not to bother about it anymore ?

Usually it's not good idea, because:

  • usually it's not that convenient to separate Transaction isolation
  • if you need to do some changes in for-loop, each of which has to have own transaction, it's also not that transparent; meanwhile on service layer you may decide whether you need the whole loop to be transactional or each of iteration;
  • tx:annotation-driven (and some other AOP-interceptor) sometimes works a bit unpredictable, if you are using AOP annotations in the controllers directly (at least I faced such issues in Spring MVC/struts2 and some other frameworks)

So basically, you have 3 layers:

  • persistence layer, which is responsible for storing/fetching data only;
  • service layer, which is responsible for data preparation and for AOP-annotations (@Transactional, @PreAuthorize, @Cacheable and so on), which use persistence layer within;
  • controller level, which gets request, binds business models, probably validates it, pass model(s) to service layer and returns result from there or handles exception

How can I have Spring or CXF bind the transaction management to the requests for me?

Please make sure, that you:

  • you have appropriate TransactionManager ('org.springframework.transaction.PlatformTransactionManager` implementation) in your config
  • you have tx:annotation-driven in your config
  • those beans are visible in the config of your CXF services
    <bean name="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    <tx:annotation-driven transaction-manager="txManager"/>

Upvotes: 3

Related Questions