views:

73

answers:

3

I've recently taken on the database/hibernate side of our project and am having terrible trouble understanding some fundamentals of our design regarding the use of managed sessions.

We have a util class containing a static session that is only initialised once. Retrieval of the session is used by every DAO in the system via a static method getBoundSession(). The application runs 24/7. Is this a common design?

One of the benefits which is extremely useful, is that lazy attributes/collections on domain objects can be used throughout the business logic tier since the session is always open. Another benefit is that the objects retreived will stay cached within the session.

I feel we must be using Hibernate in the wrong way, it just doesn't seem right to have a single permanently open session. Also it causes problems when separate threads are using the util class, hence sharing the session. On the flip side I can't find a way to achieve the above benefits (particularly the first) with a different design. Can anyone shed any light on this?

Thanks

James

+1  A: 

Keeping a session open for an extended period of time is OK (although that should not be eternity :-) A session should identify a unit of work - a coherent set of queries / updates which logically belong together. Can you identify such units in your app - e.g. client requests or conversations? If so, create a separate session for each of these.

You should also definitely use a separate session per thread (typically a unit of work is handled by a single thread anyway). A simple way to achieve this is using thread local storage.

Péter Török
A: 

It's an anti-pattern.

If you use one session for all requests. Then consider 100 clients (100 requests/threads) running almost simultaneously. You detach something from the session, but then another user reloads the same thing. You will need syncrhonization, which will hit performance. And you will have totally random behaviour that will be nightmare to debug.

The SessionFactory is static / per-application, not the Session. The factory should build a session whenever required. Read sessions and transactions docs at hibernate.

Bozho
+2  A: 

We have a util class containing a static session that is only initialised once. Retrieval of the session is used by every DAO in the system via a static method getBoundSession(). The application runs 24/7. Is this a common design?

Not it's not. The most common pattern in a multi-user client/server application is session-per-request and a session-per-application approach in a multi-user application is not only an anti-pattern, it's totally wrong:

  • A Session is not thread-safe.
  • You should rollback a transaction and close the Session after an Hibernate exception if you want to keep object state and database in sync.
  • The Session will grow indefinitely if keep it open too long.

You really need to read the whole Chapter 11. Transactions and Concurrency.

On the flip side I can't find a way to achieve the above benefits (particularly the first) with a different design.

Either use the OSIV (Open Session In View) pattern or load explicitely what you need per flow. And if you want to benefit from global caching, use the second level cache.

Pascal Thivent
Thanks very much for your response. I will definitely go away and read Chapter 11. One last question if you don't mind: We have a class hierarchy that is 7 classes deep (often one to many relations) and I'm worried that explicitly loading this hierarchy will be extremely expensive without lazy loading. Is it a design flaw to have such a tightly coupled domain model? I think this must have been teh reasoning behind our static sessions.
James
@James: I didn't mean to say "don't use lazy loading" but to *fetch* required data explicitly if you don't use the OSIV pattern. And no, I don't think that your design is flawed.
Pascal Thivent
Say we had a heirarchy: 'Customer' has-many 'Order' has-many 'Product' has-many 'Material'Since we've been using a static Session, in the bus logic a customer is loaded, passed from method to method lazy-loading members many times - say to calc the number of products per order, and the most expensive Material in an order.If the session is closed lazy-loading is useless so the business logic can't navigate the object graph. So I can only think of the business tier managing sessions (which seems bad?) or remove the depth of Customer and add DAOs to for example find most expensive material.
James
@James Lazy loading means that, when NHibernate loads a Customer, it will _not_ load any Orders (or Products or Materials) unless / until you try to access the Orders collection (which you can do only while Customer is still "attached" to an open ISession).
apollodude217
@James I think the feature you want to set up is second level caching. That will keep a cache in the SessionFactory which the Session will look to for loaded objects before it hits the DB. (I have never used second-level caching.)
apollodude217