2

I noticed that the following is not working in a class marked as a @Controller:

@Autowired
SessionFactory sessionFactory;

@ResponseBody
@Transactional
@RequestMapping(method = RequestMethod.GET , value = "/map")

public ArrayList<PhotoDTO> getPhotos(...someParams) {
   Entity result sessionFactory.getCurrentSession()... //do some manipulation

  return result;
}

when I call the URL, I get an error saying that the method is not transactional (although, as you can see, it is marked as one)

If I copy this method to a another class called MyService and call it from the controller instead, it works perfectly

Is this some sort of a Spring advice (a conspiracy to make me use more classes more or less)?

Preslav Rachev
  • 3,983
  • 6
  • 39
  • 63

2 Answers2

9

Don't do transactions in your controller. Put them in your service layer classes.

Separate your code into model-view-controller.

Yes it is a conspiracy. It enables to you to share code between controllers/views without repeating code. And also stops rollbacks of transactions unnecessarily (for exceptions unrelated to the actual transaction).

It might seem like more code to begin with, but in the long run it is much more manageable and simpler to develop.

NimChimpsky
  • 46,453
  • 60
  • 198
  • 311
  • It is kinda counter intuitive, because it is usually the controller where you make a bunch of permissions tests to say whether the current user can do a certain action. For many of those I need access to the data from DB. Alternatively, I can put move those tests in the service layer as well, but then, what is the purpose of the controller :) – Preslav Rachev Mar 13 '12 at 08:43
  • Sometimes, for basic CRUD, it seems like overkill to build a service layer just to proxy calls to basic DAO method like save or update... – Pierre Henry Nov 06 '13 at 17:18
  • @PierreHenry oooo, I agree. Had many a discussion on here about that. – NimChimpsky Nov 06 '13 at 18:09
9

Probably you have two application contexts here: main Spring context loaded by ContextLoaderListener and a child context loaded by DispatcherServlet. You need to put <tx:annotation-driven /> in the configuration loaded by the child context too. If you show us your web.xml file maybe I can help you more.

Anyway, as @NimChimpsky says, is usually not a good practice to manage transactions in your controller layer.

sinuhepop
  • 20,010
  • 17
  • 72
  • 107