Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inject Session object to DAO bean instead of Session Factory?

In our application we are using Spring and Hibernate.

In all the DAO classes we have SessionFactory auto wired and each of the DAO methods are calling getCurrentSession() method.

Question I have is why not we inject Session object instead of SessionFactory object in prototype scope? This will save us the call to getCurrentSession.

I think the first method is correct but looking for concrete scenarios where second method will throw errors or may be have bad performance?

like image 867
PrathameshMone Avatar asked May 31 '13 02:05

PrathameshMone


2 Answers

When you define a bean as prototype scope a new instance is created for each place it needs to be injected into. So each DAO will get a different instance of Session, but all invocations of methods on the DAO will end up using the same session. Since session is not thread safe it should not be shared across multiple threads this will be an issue.

For most situations the session should be transaction scope, i.e., a new session is opened when the transaction starts and then is closed automatically once the transaction finishes. In a few cases it might have to be extended to request scope.

If you want to avoid using SessionFactory.currentSession - then you will need to define your own scope implementation to achieve that.

This is something that is already implemented for JPA using proxies. In case of JPA EntityManager is injected instead of EntityManagerFactory. Instead of @Autowired there is a new @PersistenceContext annotation. A proxy is created and injected during initialization. When any method is invoked the proxy will get hold of the actual EntityManager implementation (using something similar to SessionFactory.getCurrentSession) and delegate to it.

Similar thing can be implemented for Hibernate as well, but the additional complexity is not worth it. It is much simpler to define a getSession method in a BaseDAO which internally call SessionFactory.getCurrentSession(). With this the code using the session is identical to injecting session.

like image 159
gkamal Avatar answered Nov 15 '22 07:11

gkamal


Injecting prototype sessions means that each one of your DAO objects will, by definition, get it's own Session... On the other hand SessionFactory gives you power to open and share sessions at will.

In fact getCurrentSession will not open a new Session on every call... Instead, it will reuse sessions binded to the current session context (e.g., Thread, JTA Transacion or Externally Managed context).

So let's think about it; assume that in your business layer there is a operation that needs to read and update several database tables (which means interacting, directly or indirectly, with several DAOs)... Pretty common scenario right? Customarily when this kind of operation fails you will want to rollback everything that happened in the current operation right? So, for this "particular" case, what kind of strategy seems appropriate?

  1. Spanning several sessions, each one managing their own kind of objects and bound to different transactions.
  2. Have a single session managing the objects related to this operation... Demarcate the transactions according to your business needs.

In brief, sharing sessions and demarcating transactions effectively will not only improve your application performance, it is part of the functionality of your application.

I would deeply recommend you to read Chapter 2 and Chapter 13 of the Hibernate Core Reference Manual to better understand the roles that SessionFactory, Session and Transaction plays within the framework. It will also teach will about Units of work as well as popular session patterns and anti-patterns.

like image 30
Anthony Accioly Avatar answered Nov 15 '22 08:11

Anthony Accioly