Help

New to Hibernate 3.0.1 is the SessionFactory.getCurrentSession() method. It allows application developers to delegate tracking of current sessions to Hibernate itself. This is fairly trivial functionality, but stuff just about any user of Hibernate had to implement themselves, or rely on third party stuff to do for them. Let's take a look at how this is implemented in Hibernate and how it might be useful.

Context Scope

I said that SessionFactory.getCurrentSession() tracks the current session on behalf of the application developer. What exactly does that mean? What is the scope in which a session is considered current? The transaction! More specifically, a JTA transaction.

Another dimension to scoping the current session is to which factory it belongs. Because Hibernate implements this internal to the SessionFactory, the current sessions are inherently tracked by that given factory. Internally, the SessionFactory maintains a Map of sessions keyed by JTA transaction. There is little overhead in this since the Map is built lazily, and only utilized during getCurrentSession() calls: if you don't use this feature, the map is never even built.

Example Usage

Imagine a simple scenario coordinating efforts between three DAOs:


public Bid myExposedCmtEjbServiceMethod(Long itemId, Double amount) {
    ItemDAO itemDAO = new ItemDAO( getSessionFactory() );
    BidDAO bidDAO = new BidDAO( getSessionFactory() );
    UserDAO userDAO = new UserDAO( getSessionFactory() );

    Item item = itemDAO.load( itemId );
    User bidder = userDAO.load( getCurrentUsername() );
    return bidDAO.create( item, amount, user );
}

How should each of the DAOs utilize the same session to perform their work? The typical pattern is to use ThreadLocals or similiar contextual storage (perhaps a JBoss TransactionLocal) to maintain the current session within that context. Furthermore, how do we know when this current session should be cleaned up?

The usual pattern to implement these functionalities is that a top-level service/method is defined as the service controller which is responsible for opening a session at the start, binding it to the contextual storage (so other collaborators can find it), and cleaning up the session at the end of the service processing. A slight twist on this is to use method interception to apply those behaviours (or aspects) on top of the service controller method. Either way, this can be a lot of work to setup requiring that we either:

  • modify all the service controller points to perform the open-bind-cleanup functionality
  • wrapping all our services (sometimes spuriously) in proxies so that we can intercept the method execution and apply those behavioural aspects

So instead, lets look at using the SessionFactory.getCurrentSession() approach:


public class ItemDAO {
    private SessionFactory sf;

    public ItemDAO(SessionFactory sf) { this.sf = sf; }

    public Item load(Long itemId) {
        return ( Item ) sf.getCurrentSession().load( Item.class, itemId );
    }

    ...
}

Here, each of the DAO collaborators simply use the getCurrentSession() method; the things collaborating with the DAOs do not need to perform anything extra and we do not need to generate proxies and method interceptors just to apply the notion of contextual sessions.

So now, by using getCurrentSession() we can easily scope the notion of a current session to the JTA transaction and reuse the same session throughout that JTA transaction. But how do we clean up the session? And how do we manage flushing of the session state with the database?

Auto flush and close

Two new configuration options introduced in Hibernate3 are extremely powerful, especially when combined with the SessionFactory.getCurrentSession(). Both of these are available in the JTA environments, as well as scenarios where application is utilizing the Hibernate transaction-abstraction API.

The first is flush_before_completion, which forces a flush of the session just prior to transaction completion (think Synchronization.beforeCompletion()...). With this setting enabled, we do not have to worry about flushing the session after we are done in order to synchronize in-memory state with the database; Hibernate does it for us (just prior the transaction commit).

The second is auto_close_session, which forces the session to be closed after transaction completion. In JTA environments, this setting has an additional effect; it forces Hibernate to release JDBC connections much more aggresively. Basically, Hibernate will obtain a connection, use it, and then immediately release it back to the datasource. This allows better integration into JTA environments which implement some form of connection containment check (i.e. the JBoss CachedConnectionManager).

Conclusion

All of these together allow application developers to free themselves from managing session lifecycle and have Hibernate do it for them.

29 comments:
 
15. Jun 2005, 05:41 CET | Link
Brian Vaughn | bfvaughn(AT)gmail.com
What if you use CMT but have your read methods trans-attribute set to Supports? Normally I don't want to create a transaction for my reads.
ReplyQuote
 
13. Apr 2005, 18:41 CET | Link
Eli
This is awsome functionality, especially for using Hibernate within session beans. Any idea as to when 3.0.1 will be released?

Thanks!

Eli
 
21. Apr 2005, 07:02 CET | Link
We implemented basically this same functionality about a year and a half ago. Nice to see it make it into the core product.

One thing that we needed in our system was the concept of nested sessions.

For example; a thread processing a request opens a session at the service entry point. This session is for the business transaction, during which many things might happen. One of those things might be an operation that needs to be persisted right away (an application level lock, for example, that can't wait until the overall business transaction completes).

Because of this we have implemented the notion of a stack of sessions that could get created throughout the lifetime of the business transaction. This stack doesn't usually get to be more than two deep. Application code always calls getCurrentSession(), getting the correct session depending on the state of the stack.

There are obviously other ways to do this, but that is the way the system has grown up over the past four years.

Do you guys have anything similar in mind?
 
14. Apr 2005, 05:24 CET | Link
Steve
3.0.1 will be released this weekend. :)
 
10. May 2005, 23:06 CET | Link
Sony Mathew
Would have been nice to have a while back. No longer an issue if you are using IoC.
 
23. Sep 2006, 00:14 CET | Link
<a href="http://www.ernestjenning.com/images/mobile-phone-deal.htm">mobilesmokinglingerieflowerflowerflowerflowerhorsefoodpillow</a>
 
03. May 2005, 19:27 CET | Link
Mathew Thomas
I am so glad this made it in to the Hibernate framework. Everything mentioned in the blog is something we had to implement in our applications custom framework (we use 2.1.7).

Also does SessionFactory.getCurrentSession() create a new Session if one is not tied to the thread? That is one thing we do in our app framework.


 
02. May 2005, 16:04 CET | Link
Ron Dagostino | ron_dagostino(AT)ssga.com
I wrote a bunch of classes to help me manage Sessions. Sessions live on threads, and each has a name. If you call new MySession("optional_name") twice they will both refer to the same underlying Session object. The MySession object effectively implements the Session interface (I copied everything but eliminated the throws clauses). The session gets created lazily, and the MySession object that causes the underlying Session object to be created "owns" the Session so that when it calls close() the underlying Session object actually closes. Other MySession objects can call close() but the underlying Session object will not close because they didn't cause it to open. There is also help for specifying XML resource names. If anyone is interested in taking a look please let me know and I will send the code. It works in hibernate 2 -- I haven't looked at hibernate 3 and do not know if it is necessary there.
 
14. Apr 2005, 05:28 CET | Link
Steve

But, if I have an environment with XA transactions, would you still recommend the useage of getCurrentSession() ?

Absolutely.
 
09. May 2005, 23:15 CET | Link
Christian
This is now relatively old news and everyone is encouraged reading the updated reference docs. I think its quite clear now how transactions and sessions are handled, the whole chapter has been rewritten for H3.

 
13. Apr 2005, 16:52 CET | Link
Steve
Funny how many times I've heard this misconception. No! You are interacting with a database; *everything* happens within the bounds of a transaction (yes, even in auto-commit mode; think about the name).

Now if the JTA transaction is also an XA transaction, then there is potentially an overhead required for the 2PC, but JTA transactions used in the majority of applications are not (or need not be) XA transactions.
 
21. Apr 2005, 08:49 CET | Link
steve
One thing that we needed in our system was the concept of nested sessions.

So how do you suspend your transactions and/or obtain a different physical connection from the datasource?



Do you guys have anything similar in mind?

Nope
 
09. May 2005, 18:26 CET | Link
Using this approach means you have a single current session per SessionFactory. I am a relative newbie to Hibernate, but from HIA I was under the impression that it was typical to have one SessionFactory and multiple concurrent Sessions. I am curious because I like the approached described here but I am wondering whether there are downsides to the "single current session" approach. I know the blog talks about this in the context of JTA but it also says that support for non-JTA env's is coming in a future release, and this is the context that would apply in my case.
 
17. Jun 2005, 14:01 CET | Link
Christian
This is not a support forum.

 
13. Apr 2005, 11:56 CET | Link
Oliver Geisser
Hi,

interesting stuff, but I wonder how dows this relate to non-JTA environments? Can you explain this, too?

Thanks, Olli
  
 
21. Apr 2005, 08:47 CET | Link
steve

Is there a getCurrentTransaction as well?

Nope, kinda silly since it curently is only supported for JTA transactions :)

Perhaps if/when we extend this to the Hibernate Transaction API...
 
20. Apr 2005, 03:01 CET | Link
Ron
Are there any special property settings necessary to enable this functionaliy.
 
24. Nov 2005, 16:56 CET | Link
Chris
Steve,

I may be in the wrong place, but i'm trying to build a small prototype showing a 2 phase commit. I'm having trouble implementing this using the hibernate(3) api. How can i make 1 transaction that takes 2 sessions (1 for each DB) where the commit does a commit on both DB's and does a rollback of the first when the second goes wrong. Using the JTA api it works, but using hibernate , i don't see any possibility.

Chris.
 
22. Jun 2005, 18:09 CET | Link
Brian Vaughn
Thanks
 
13. Apr 2005, 17:25 CET | Link
Bernhard
Thanks for this insight!

But, if I have an environment with XA transactions, would you still recommend the useage of getCurrentSession() ?

Thanks, Bernhard
  
 
17. Jun 2005, 17:08 CET | Link
Jakob Braeuchi
i know, i just answered brian's question about the trans-attribute ;)
 
14. Apr 2005, 18:20 CET | Link
Behrang
Offtopic Question:

Is it possible to create a mailing list for Hibernate?
 
13. Apr 2005, 16:40 CET | Link
Bernhard
Is it not a performance problem, to start always a transaction?

Bernhard
 
14. Apr 2005, 02:28 CET | Link
Shanu
We are using Hibernate 3.0 production and were in the design phase of creating precisely this functionality. It would really help if we could use 3.0.1, or if that would be in the future, we could just take the changed files.
We also tried to search for the getCurrentSession() method in the CVS source but did not find it.
 
13. Apr 2005, 15:34 CET | Link
Steve
In 3.0.1, it won't work (you'll actually get an exception attempting to call getCurrentSession()) in non-JTA envs.

We plan on adding support additionally for applications using the Hibernate Transaction API. That is currently targetted for 3.0.2 or 3.1.

In non-JTA envs where the app is not using the Hibernate Transaction API, there is not much we can do.
 
17. Jun 2005, 10:07 CET | Link
Jakob Braeuchi
i get an exception "unable to locate current JTA Transaction" when using "Supports". the behaviour is the same for org.hibernate.transaction.CMTTransactionFactory and org.hibernate.transaction.JTATransactionFactory.
 
20. Apr 2005, 09:41 CET | Link
Friso
Hi there,

Is there a getCurrentTransaction as well?

I want this because I want control over my commit. Perhaps to catch exceptions that happen commit-time, perhaps to lessen the load per transaction. Here I mean that when doing a lot of updates, I found it a lot faster to commit, close and start a session and than build a new transaction, than to do it all in one transaction.

Any thoughts on this?

Groeten,

Friso
 
04. Oct 2007, 12:40 CET | Link
Arif

Hi,

Iam having a requirement where a parent thread opens multiple child threads.Each child thread makes use of hybernate session(iam using getCurrentSession).If any thing is wrong with any of the threads all the processing of other threads should get rollback.Iam using Transaction Manager to control the trasactions.

But it is said that hibernate session object can't be used by multiple concurrent threads.But i want this functionality.Is there any way i can achieve this?

 
04. Oct 2007, 12:49 CET | Link
Arif

Hi,

Iam having a requirement where a parent thread opens multiple child threads.Each child thread makes use of hybernate session(iam using getCurrentSession).If any thing is wrong with any of the threads all the processing of other threads should get rollback.Iam using Transaction Manager to control the trasactions.

But it is said that hibernate session object can't be used by multiple concurrent threads.But i want this functionality.Is there any way i can achieve this?

Post Comment