1

I have been using the session factory (Singleton Bean injected into the DAO objects) in my Spring/Hibernate application, I am using the service layers architecture, and I have the following issue:

Anytime I get a domain object from the database, it uses a new session provided by the hibernate session factory. In the case of requesting several times the same row, this leads to having multiple instances of that same domain object. (If using a single session, it would return multiple objects pointing to the same reference) Thus, any changes made to one of those domain object is not taken into account by the other domain objects representing this same row.

I am developing a SWING application with multiple views and I get the same DB row from different locations (And queries), and I thus need to obtain domain objects pointing to the same instance.

My question is then, Is it a way to make this happen using the SessionFactory? If not, is it a good practice to use a single session for my whole application? In that case, how and where should I declare this session? (Should it be a bean injected into the DAO objects just like the sessionFactory?)

Thank you in advance for your help

2 Answers2

0

Hibernate session (I will call it h-session) in Spring usually bound to thread (see JavaDoc for HibernateTransactionManager), so h-session acquired once per thread.

First level cache (h-session cache - always turned on) used to retrieve same object if you call "get" or "load" several times on one h-session. But this cache doesn't work for queries.

Also, you shouldn't forget about problems related to transaction isolation. In most applications "Read committed" isolation level is used. And this isolation level affected by phenomenon known as "non-repeatable reads". Basically, you could receive several versions of the same row in one transaction if you query for this row several times (because row could be updated between queries in another transaction).

So, you shouldn't query several times for same data in one h-session/transaction.

Vadim Ponomarev
  • 1,338
  • 9
  • 15
  • Hi Vadim, Thanks for your answer. The problem is that I have multiple Views (threads) that are requesting a same row in the database. Anytime they do so, they call the Service layer that himself calls the DAO layer. (Service and DAO classes are bean singletons and are injected by Spring) The DAO layer then opens a new h-session, (through the session factory) retrieves the row from the database and then closes the h-session. I am then accessing the same DB row from different views (threads) and I end up with multiple instances of the same DB row instead of multiple references to that same row. – user1373769 May 05 '12 at 19:43
  • When using a single session, anytime I query a DB row, it returns me the same instance of a domain object if this one has already been requested earlier. I need this to be the case too using different sessions. (Through the Session factory) If impossible, I'll need to use the same session from start to end of my application, and I'm not sure how to do it. Can the session be a been singleton that is injected into the DAO classes? I would then have to open it in my main class before anything happens and let spring inject it when DAO methods are called? Thank in advance – user1373769 May 05 '12 at 19:48
  • What do you mean by multiple Views? Several windows? And you want to immediately sync data between windows if it's updated in one of them? – Vadim Ponomarev May 05 '12 at 19:48
  • Actually, Spring workflow designed to work on application server serving multiple requests in multiple threads simultaneously. If you have one-thread application you could work directly with Hibernate (open session, handle transactions). – Vadim Ponomarev May 05 '12 at 20:03
  • But, quote from Hibernate documentation about Session: `The lifecycle of a Session is bounded by the beginning and end of a logical transaction.` – Vadim Ponomarev May 05 '12 at 20:06
  • You could query all data required for views with data intersection in the same transaction/h-session and after that update those views with acquired data. – Vadim Ponomarev May 05 '12 at 20:22
0

You're looking for the Open Session in View Pattern. Essentially, you want to bind a Session to your thread on application startup and use the same Session throughout the lifetime of the application. You can do this by creating a singleton util class which keeps a session like so (note that the example I have uses an EntityManager instead of a Session, but your code will be essentially the same):

  private static EntityManager        entityManager;

  public static synchronized void setupEntityManager() {
    if (entityManager == null) { 
      entityManager = entityManagerFactory.createEntityManager();
    } 

    if (!TransactionSynchronizationManager.hasResource(entityManagerFactory)) {
      TransactionSynchronizationManager.bindResource(entityManagerFactory, new EntityManagerHolder(entityManager));
    }
  }

  public static synchronized void tearDownEntityManager() {
    if (entityManager != null) { 
      if (entityManager.isOpen()) { 
        entityManager.close();
      } 

      if (TransactionSynchronizationManager.hasResource(entityManagerFactory)) { 
        TransactionSynchronizationManager.unbindResource(entityManagerFactory);
      } 

      if (entityManagerFactory.isOpen()) { 
        entityManagerFactory.close();
      } 
    } 
  }

Note that there are inherent risks associated with the Open Session in View pattern. For example, I noticed in the comments that you intend to use threading in your application. Sessions are not threadsafe. So you'll have to make sure you aren't trying to access the database in a threaded manner.*

You'll also have to be more aware of your fetching strategy for collections. With an open session and lazy loading there's always the chance that you'll put undue load on your database.

*I've used this approach in a NetBeans application before, which I know uses threading for certain tasks. We never had any problems with it, but you need to be aware of the risks, of which there are many.

Edit

Depending on your situation, it may also be possible to evict your domain objects from the Session and cache the detached objects for later use. This strategy would of require that your domain objects not be updated very often, otherwise your application would become unnecessarily complicated.

Tim Pote
  • 24,528
  • 6
  • 58
  • 63
  • Open Session in View used to resolve "lazy loading" problem. But author of question doesn't have problem with "lazy loading" (at least not yet). Also check this [SO-question](http://stackoverflow.com/questions/1103363/why-is-hibernate-open-session-in-view-considered-a-bad-practice). – Vadim Ponomarev May 05 '12 at 20:26
  • @VadimPonomarev Open Session in View happens to also resolve the OP's issue, which is making sure all of his views have access to the same domain objects, i.e. the same Session. The problem is one in the same. I am also aware of the issues with OSIV. Two of the issues listed in your linked question are distinct to web applications. I mentioned the third (fetching strategies/database load) in my answer. – Tim Pote May 05 '12 at 20:39