5
votes

I am using Spring 3.1 and have my DAO and service layer(transactional) written.

However in a special case to avoid a lazy init exception I have to make a spring mvc request handler method @transactional. But It is failing to attach transaction to that method. Method name is ModelAndView home(HttpServletRequest request, HttpServletResponse response). http://forum.springsource.org/showthread.php?46814-Transaction-in-MVC-Controller From this link it seems it is not possible to attach transaction (by default ) to mvc methods. Solution suggested in that link seems to be for Spring 2.5 (overriding handleRequest ). Any help will be reallyappreciated. Thanks

@Controller
public class AuthenticationController { 
@Autowired
CategoryService categoryService;    
@Autowired
BrandService brandService;
@Autowired
ItemService itemService;

@RequestMapping(value="/login.html",method=RequestMethod.GET)
ModelAndView login(){       
    return new ModelAndView("login.jsp");       
}   
@RequestMapping(value="/home.html",method=RequestMethod.GET)
@Transactional
ModelAndView home(HttpServletRequest request, HttpServletResponse response){
    List<Category> categories = categoryService.readAll();
    request.setAttribute("categories", categories);     
    List<Brand> brands = brandService.readAll();
    request.setAttribute("brands", brands);     
    List<Item> items = itemService.readAll();
    request.setAttribute("items", items);
    Set<Image> images = items.get(0).getImages();
    for(Image i : images ) {
        System.out.println(i.getUrl());
    }
    return new ModelAndView("home.jsp");    
}
3
What you are trying to rollback here? On the controller function where you have defined the @Transaction annotation there is no such database operation that can be rolled back. Im confused. - Japan Trivedi
all the service calls like categoryService.readAll() are database operations - Subin Sebastian
Ya but you can not roll back the read data. What are you exactly trying to roll back? - Japan Trivedi
It is still useful to wrap the home method in a transaction as it'll help in sharing database connections potentially - Kieran
yes good point that connections will be shared, also lazy loading works only within same session. - Subin Sebastian

3 Answers

4
votes

You'll need to implement an interface so that Spring has something it can use as a Proxy interface:

@Controller
public interface AuthenticationController {
  ModelAndView home(HttpServletRequest request, HttpServletResponse response);
}

@Controller
public class AuthenticationControllerImpl implements AuthenticationController {

@RequestMapping(value="/home.html",method=RequestMethod.GET)
@Transactional
@Override
ModelAndView home(HttpServletRequest request, HttpServletResponse response){
.....
}
}
4
votes

Spring will implement the transactional logic using JDK dynamic proxies, these rely on proxied classes implementing suitable interfaces. It's also possible to use CGLib proxies which don't require interfaces.

There is a nice article about this link

0
votes

I'm not sure this applies to your case but if you are using separate DI contexts you should also consider how Spring weaves aspects.

Spring will only apply @Transactional semantics to beans in the same DI context where @EnableTransactionManagement or <tx:annotation-driven/> is used.

So if you define your transaction configuration in the root context, only beans in that context are covered, which typically means only business services. You'll need to re-enable transaction management in any child context where you also use @Transactional.

Ref: Spring AOP - How to make aspects defined in a parent context work in child contexts?