-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 
Author Message
 Post subject: handling session
PostPosted: Thu Apr 12, 2007 7:01 am 
Newbie

Joined: Mon May 08, 2006 12:14 am
Posts: 18
Hi,

We are developing a web application which uses hibernate for data persistence. There is a confusion regarding when to open and close hibernate session. We are planning to use JNDI bound session factory. Is it a good practice to call sessionFactory.openSession() within the methods in the DAO class and call session.close() in the finally block in those methods? I have read that filters also can be used for that. We are confused on which method to adopt. Please give your valuable suggestions on this.

This is a sample code we wrote in the DAO class:


public void persist(TestEntity transientInstance) {
try {
HibernateUtil.beginTransaction();
HibernateUtil.getCurrentSession().save(transientInstance);
HibernateUtil.commitTransaction();
} catch (RuntimeException re) {
re.printStackTrace();
}finally {
HibernateUtil.closeSession();
}
}

This is our HibernateUtil class:

public class HibernateUtil {

private static SessionFactory sessionFactory;
private static final ThreadLocal threadSession = new ThreadLocal();
private static final ThreadLocal threadTransaction = new ThreadLocal();

public static Session getCurrentSession() {

Session s = (Session) threadSession.get();

// Open a new Session, if this thread has none yet
try {
if (s == null) {
InitialContext ic=new InitialContext();
// JNDI bound session factory
sessionFactory=(SessionFactory)ic.lookup("java:hibernate/SessionFactory");
s = sessionFactory.openSession();
threadSession.set(s);
}
} catch(NameNotFoundException nnfe) {
// For situations where JNDI bound session factory is not supported
sessionFactory = new Configuration().configure("hibernate.cfg.xml").buildSessionFactory();
s = sessionFactory.openSession();
threadSession.set(s);
} catch(NamingException ne) {
System.out.println(ne.toString());
} catch (HibernateException ex) {
System.out.println(ex.toString());
}
return s;
}

public static void closeSession() {

try {
Session s = (Session) threadSession.get();
threadSession.set(null);
if (s != null && s.isOpen()) {
s.close();
}
} catch (HibernateException ex) {
System.out.println(ex.toString());
}
}

public static void beginTransaction() {

Transaction tx = (Transaction) threadTransaction.get();
try {
if (tx == null) {
tx = getCurrentSession().beginTransaction();
threadTransaction.set(tx);
}
} catch (HibernateException ex) {
System.out.println(ex.toString());
}
}

public static void commitTransaction() {

Transaction tx = (Transaction) threadTransaction.get();
try {
if(tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
tx.commit();
}
threadTransaction.set(null);
} catch (HibernateException ex) {
rollbackTransaction();
}
}

public static void rollbackTransaction() {

Transaction tx = (Transaction) threadTransaction.get();
try {
threadTransaction.set(null);
if ( tx != null && !tx.wasCommitted() && !tx.wasRolledBack() ) {

tx.rollback();
}
} catch (HibernateException ex) {
System.out.println(ex.toString());
} finally {
closeSession();
}
}
}

Thanks & Regards
Merin


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 12, 2007 9:25 am 
Expert
Expert

Joined: Tue Jul 11, 2006 10:21 am
Posts: 457
Location: Columbus, Ohio
Merin:

You definitely do not want to do this:
Code:
public void persist(TestEntity transientInstance) {
try {
HibernateUtil.beginTransaction();
HibernateUtil.getCurrentSession().save(transientInstance);
HibernateUtil.commitTransaction();
} catch (RuntimeException re) {
re.printStackTrace();
}finally {
HibernateUtil.closeSession();
}
}


Your DAO should not be starting and committing transactions, the transactions should encapsulate your business logic. For instance, what would happen if your business rules required two separate entities be persisted with rollback on both in case of failure. That's why I always code a service layer and deal with transactions there. If your project is small enough, you can get away with dealing with transactions directly in your MVC layer.

As far as session management is concerned, it really depends on how you want to code your MVC layer. If you would like to lazy load things in your view, then you are best off using a servlet filter to open and close the sessions in the filter chain (this is typically called an Open Session In View filter) and you can find the details here: http://www.hibernate.org/43.html . The thread local pattern that you are currently using is a bit deprecated, in that the Hibernate session can be bound to a thread automatically, see http://www.hibernate.org/hib_docs/v3/re ... nt-session for information about the contextual sessions. That way, any call to SessionFactory.getCurrentSession() will return the thread (or JTA) bound Session. This is a nice pattern to use, check out the CaveatEmptor demo application for a more updated HibernateUtils. Happy coding!


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 16, 2007 4:37 am 
Newbie

Joined: Mon May 08, 2006 12:14 am
Posts: 18
Hi Ananasi,

Thanks for your response. I understand from your reply that beginTransaction and commit should not be done in DAOs. Servlet Filter also seems to be a bad choice. I actually don't like to use filter because all requests may not require a database transaction.

According to you,
>>That's why I always code a service layer and deal with transactions there.

What do you mean by service layer and how do you implement that? Could you please send a sample code? Our application has a presentation layer and business implementation layer before dao layer. Which is the best place to include the transaction code?

Is JTA the best option for a web application?

Is this code ok?

try {
UserTransaction tx = (UserTransaction)new InitialContext() .lookup("java:comp/UserTransaction");
tx.begin();
// Do some work
factory.getCurrentSession().load(...);
factory.getCurrentSession().persist(...);
tx.commit();
} catch (RuntimeException e) {
tx.rollback();
throw e; // or display error message
}

I am really confused on how to proceed. Please help.

Thanks & Regards
Merin
[/quote]


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 16, 2007 9:20 am 
Expert
Expert

Joined: Tue Jul 11, 2006 10:21 am
Posts: 457
Location: Columbus, Ohio
1) If you have JTA available, I would definitely use that. Set the hibernate.current_session_context_class property to "jta" and whenever you start a JTA transaction, the getCurrentSession() call will return the Hibernate session bound to that JTA transaction automatically (session-per-request semantics). From the javadocs of org.hibernate.context.JTASessionContext:

Javadocs wrote:
If a session is not already associated with the current JTA transaction at the time currentSession() is called, a new session will be opened and it will be associated with that JTA transaction.

Note that the sessions returned from this method are automatically configured with both the auto-flush and auto-close attributes set to true, meaning that the Session will be automatically flushed and closed as part of the lifecycle for the JTA transaction to which it is associated. Additionally, it will also be configured to aggressively release JDBC connections after each statement is executed.


2) Service layer = business layer, it's just semantic differences. Definitely start and commit your transactions there to encapsulate your business logic. For example:

Code:
public void saveMyData(MyData myData) {
  UserTransaction tx = HibernateUtils.beginTransaction();
  if (businessRequirementsMet) {
    HibernateUtil.getSessionFactory().getCurrentSession().persist(myData);
  } else {
    // Handle business rules/validation errors
  }
  try {
    tx.commit();
  } catch (Exception e) {
    tx.rollback();
    // Do commit error handling here
  } 
}

If you want, you can still use the thread bound transaction demarcation (the ThreadLocal in your current HibernateUtils) to begin, commit and rollback transactions as needed, providing further abstraction, which would make the code look like this:

Code:
public void saveMyData(MyData myData) {
  HibernateUtils.beginTransaction();
  if (businessRequirementsMet) {
    HibernateUtil.getSessionFactory().getCurrentSession().persist(myData);
  } else {
    // Handle business rules/validation errors
  }
  try {
    HibernateUtils.commitTransaction();
  } catch (Exception e) {
    HibernateUtils.rollbackTransaction();
    // Do commit error handling here
  } 
}


Again, check out http://www.hibernate.org/400.html and look at the HibernateUtils class there (auction.persistence.HibnerateUtil). It's the best start, notice the lack of ThreadLocal variables to hold a Session.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.