Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to configure and get session in Hibernate 4.3.4.Final?

I recently upgraded the version of my Hibernate to 4.3.4.Final. Based on Contextual Sessions configuration of Hibernate this new version is not based on ThreadLocal anymore. If what I have got so far is correct do I need to do anything to make it more efficient? if it is incorrect what should I do? I have no clue.

Please note it is mentioned in documentation that: Hibernate offers three methods of current session tracking. The "thread" based method is not intended for production use; it is merely useful for prototyping and tutorials such as this one.

Hibernate.cfg.xml

<hibernate-configuration>

    <session-factory>

    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost/myDB</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password"></property>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <!-- Enable Hibernate's automatic session context management -->
    <property name="current_session_context_class">thread</property>

    <!-- Disable the second-level cache  -->
    <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

    <property name="show_sql">true</property>

    <property name="hibernate.c3p0.min_size">5</property>
    <property name="hibernate.c3p0.max_size">20</property>
    <property name="hibernate.c3p0.timeout">300</property>
    <property name="hibernate.c3p0.max_statements">50</property>
    <property name="hibernate.c3p0.idle_test_period">3000</property>
        <!--        <property name="hbm2ddl.auto">update</property>-->

        <mapping class="com.myProject.entities.users" />
        ...

Current Configuration and Code

Based on answers blew and this part of documentation mu current configuration is as following:

 public class HibernateUtil {

    private static SessionFactory sessionFactory = buildSessionFactory();

    private static SessionFactory buildSessionFactory() {
        try {
              Configuration configuration = new Configuration();
              return configuration.configure()
                                  .buildSessionFactory(
                                       new StandardServiceRegistryBuilder()  
                                          .applySettings(configuration.getProperties())
                                          .build());
        } catch (Throwable ex) {
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

}

And the code would be as following

    final Session session = HibernateUtil.getSessionFactory().openSession();
    try {
        final Transaction tx = session.beginTransaction();
        try {
              ...

Previous Configuration and Code

public class HibernateUtil {

    private static ServiceRegistry serviceRegistry;
    private static final ThreadLocal<Session> threadLocal = new ThreadLocal();
    private static SessionFactory sessionFactory;

    private static SessionFactory configureSessionFactory() {
        try {
            Configuration configuration = new Configuration();
            configuration.configure();
            serviceRegistry = new StandardServiceRegistryBuilder()
                    .applySettings(configuration.getProperties())
                    .build();
            sessionFactory = configuration.buildSessionFactory(serviceRegistry);
            return sessionFactory;
        } catch (HibernateException e) {
            System.out.append("** Exception in SessionFactory **");
            e.printStackTrace();
        }
        return sessionFactory;
    }

    static {
        try {
            sessionFactory = configureSessionFactory();
        } catch (Exception e) {
            System.err.println("%%%% Error Creating SessionFactory %%%%");
            e.printStackTrace();
        }
    }

    private HibernateUtil() {
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public static Session getSession() throws HibernateException {
        Session session = threadLocal.get();

        if (session == null || !session.isOpen()) {
            if (sessionFactory == null) {
                rebuildSessionFactory();
            }
            session = (sessionFactory != null) ? sessionFactory.openSession() : null;
            threadLocal.set(session);
        }

        return session;
    }

    public static void rebuildSessionFactory() {
        try {
            sessionFactory = configureSessionFactory();
        } catch (Exception e) {
            System.err.println("%%%% Error Creating SessionFactory %%%%");
            e.printStackTrace();
        }
    }

    public static void closeSession() throws HibernateException {
        Session session = (Session) threadLocal.get();
        threadLocal.set(null);
        if (session != null) {
            if (session.isOpen()) {
                session.close();
            }
        }
    }
}

Code to access to transactions and submit commands

 final Session session = HibernateUtil.getSession();
        try {
            final Transaction tx = session.beginTransaction();
            try {

                    //Commands related to query go here

             if (!tx.wasCommitted()) {
                    tx.commit();
                }

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

                return true;
            } catch (Exception e) {
                tx.rollback();
                return false;
            }
        } finally {
            HibernateUtil.closeSession();
        }
        return false;
like image 528
Jack Avatar asked May 14 '14 05:05

Jack


1 Answers

I would drop the TreadUtil class which reminds me of the Spring 1.0 Hibernate integration style. If you plan on moving to Hibernate 4.

Beside the fact that you should rely on Hibernate 4 bootstrap mechanism, your code also has the following problems:

  1. The session factory rebuilding is not synchronized

        synchronized(HibernateUtil.class) {
        if (sessionFactory == null) {
            rebuildSessionFactory();
        }
    }
    
  2. I don't see why you need to rebuild it, since you never set it to null, the session factory being initialized static block.

If you always have to wrap your Hibernate code in the HibernateUtil.openSession() try/finally blocks, you would duplicate a lot of session management logic while mixing business logic with transaction logic. This breaks the single responsibility principle.

If you still don't want to let the HibernateUtil go, you can at least use a mechanism similar to JDBCTemplate to abstract the session/transaction management in a template method, while supplying the business code in a Callable, which for you might look like:

interface SessionCallback<T> {T doInSession(Session session);}

class HibernateUtil {

    public T execute(SessionCallback<T> action) {
        try{
            //open session
            //open transcation
            T result = action.doInSession(sessionFactory.getCurrentSession());
            //commit tx



            return result;
        }
        catch(RuntimeException e) {
            //rollback tx
            throw e;
        }
        finally {
            //close session
        }
    }
}

HibernateUtil.execute(new SessionCallback<Void>() {
    public Void doInSession(Session session) {
        session.createQuery(...);
        return null;
    }
});

final customerID = ...

Customer customer = HibernateUtil.execute(new SessionCallback<Customer>() {
    public Customer doInSession(Session session) {
        return (Customer) session.get(Customer.class, customerID);
        return null;
    }
});

Looking at your code indicates you want JDBC resource local transactions with the session-per-request access idiom, meaning you need the ThreadLocalSessionContext:

hibernate.current_session_context_class=thread
hibernate.transaction.factory_class=JDBCTransactionFactory

Extra

You might consider switching to JPA as well and moving the Hibernate properties to persistence.xml.

like image 127
Vlad Mihalcea Avatar answered Oct 31 '22 22:10

Vlad Mihalcea