I’ve been learning how to use the Spring framework for hibernate transaction management, and so far it has been a great help for that purpose. The problem is that recently, I realized that I hadn’t been giving much thought to how the pattern that I chose handles concurrency, specially in the case of a web application.
Below is the code that exemplifies the pattern that I’m using, which is a combination of some examples I found, and a custom servlet implementation. I have a few doubts about how this pattern works and whether it is thread-safe since I customized it a bit. Some of my concerns are:
- Even though servlets are technically not singletons, I’m under the impression that most of the time there will be only a single instance for each servlet class.
- If I understand correctly, each auto-wired property will be a singleton, so if the above its true, then there’ll be a single servlet instance with a single service instance, which in turn has a single DAO instance, which has its own SessionFactory instance.
- If the above is correct then I can imagine that every request on the servlet will be using the same objects and I wonder whether this is a good thing. After giving it some thought I can’t tell whether it would be better for thread-safety to have singletons or to have new instances created for each http request.
- Usually these spring patterns have a @Controller class which I skipped in favor of our custom servlet and I’m wondering whether that could break the concurrency of the pattern somehow.
Thanks
public interface UserDAO
{
public void save(User user);
}
@Repository
public class HibernateUserDAO implements UserDAO
{
@Autowired(required=true)
protected SessionFactory sessionFactory;
public void save(User user)
{
this.sessionFactory.getCurrentSession().save(user);
}
}
public interface UserService
{
public void saveUser(User user);
}
@Service
public class DefaultUserService implements UserService
{
@Autowired(required=true)
private UserDAO userDAO;
@Transactional
public void saveUser(User user)
{
this.userDAO.save(user);
}
}
public class UserServlet extends CustomServlet
{
@Autowired(required=true)
private UserService userService;
public void init() throws ServletException
{
super.init();
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
//would call the appropriate method depending on parameters, etc.
//simplified here for demonstration purposes
this.userService.saveUser(user);
}
}
If you have a suitable strategy set up in the Hibernate configuration, then
sessionFactory.getCurrentSession()will return a scoped session, not a global one. Session factories are intended to be singletons, that’s quite correct;getCurrentSession()is the usual method to bridge to the current context scope.“suitable strategy” varies, but if you’re using the spring transaction management wrapped around your DAO, then a session will have a lifetime of a DAO method call, and Spring will orchestrate calling commit/rollback as appropriate on exit.