1
\$\begingroup\$

I have this HibernateDAO.java Class:

public abstract class HibernateDAO implements DAO {

    private static final SessionFactory sessionFactory;

    private static final ThreadLocal<Session> session = new ThreadLocal<Session>();

    private static final ThreadLocal<Transaction> transaction = new ThreadLocal<Transaction>();

    static {
        try {
            Configuration c = new Configuration().configure();
            sessionFactory = c.buildSessionFactory();
            } catch (Exception ex) {
            throw new RuntimeException("Problème de configuration : " + ex.getMessage(), ex);
        }
        if (sessionFactory == null) {
            throw new RuntimeException("Problème de configuration : La factory Hibernate n'as pas été configurée");
        }
    }

    public Session currentSession() {
        Session s = (Session) session.get();
        // Ouvre une nouvelle Session, si ce Thread n'en a aucune
        if (s == null) {
            s = sessionFactory.openSession();
            session.set(s);
        }
        return s;
    }

    private void closeSession() {
        Session s = (Session) session.get();
        session.set(null);
        if (s != null && s.isOpen()) {
            s.close();
        }
    }

    public void commitTransaction() throws PersistenceException {
        Transaction t = (Transaction) transaction.get();
        if (t == null) {
            throw new PersistenceException("Pas de transaction ouverte");
            } else if (session.get().getTransaction().getStatus() !=  TransactionStatus.ACTIVE) { 
            throw new PersistenceException("Transaction déjà fermée");
        }
        t.commit();
        transaction.set(null);
        closeSession();
    }

    public void openTransaction() throws PersistenceException {
        Transaction t = (Transaction) transaction.get();
        if (t != null) {
            throw new PersistenceException("Transaction déjà ouverte");
        }
        t = currentSession().beginTransaction();
        transaction.set(t);
        flush();
    }

    public void rollbackTransaction() throws PersistenceException {
        Transaction t = (Transaction) transaction.get();
        if (t == null) {
            throw new PersistenceException("Pas de transaction ouverte");
            } else if (session.get().getTransaction().getStatus() !=  TransactionStatus.ACTIVE) { 
            throw new PersistenceException("Transaction déjà fermée");
        }
        t.rollback();
        transaction.set(null);
        closeSession();
    }

    public boolean isTransactionOpened() {
        Transaction t = (Transaction) transaction.get();
        return (t!=null);
    }

    public void flush() {
        currentSession().clear();
        currentSession().flush();
    }

    protected void save(Object o) {
        currentSession().save(o);
    }

    protected void delete(Object object) {
        currentSession().delete(object);
    }

    protected Object load(Class theClass, Integer id) {
        return currentSession().load(theClass, id);
    }

    protected Query createQuery(String query) {
        return currentSession().createQuery(query);
    }

}

hibernate.cfg.xml:

<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory name="">
        <!-- Start of user code for Hibernate configuration parameters -->
        <property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
        <property name="hibernate.connection.driver_class">org.postgresql.Driver</property>
        <property name="hibernate.connection.url">jdbc:postgresql://xxxxx/xxxx</property>
        <property name="hibernate.connection.username">xxxx</property>
        <property name="hibernate.connection.password">xxxxx</property>
        <property name="show_sql">true</property>
        <property name="hibernate.default_schema">xxxxxx</property>
        <property name="transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
        <property name="hibernate.jdbc.batch_versioned_data">false</property>
        <!-- <property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>-->
        <property name="hibernate.hbm2ddl.auto">update</property>
        <property name="hibernate.c3p0.max_size">20</property>
        <property name="hibernate.c3p0.max_statements">5</property>
        <property name="hibernate.c3p0.min_size">1</property>
        <property name="hibernate.c3p0.timeout">300</property>
        <mapping resource="mapping.hbm.xml"/>
    </session-factory>
</hibernate-configuration>

I use:

  • hibernate-core-5.0.7.Final
  • hibernate-jpa-2.1-api-1.0.0.Final
  • hibernate-commons-annotations-5.0.1.Final

I wanted to know if this class could be improved?

\$\endgroup\$
  • \$\begingroup\$ Are you using some other framework like Spring or CDI? \$\endgroup\$ – Xtreme Biker Apr 29 '16 at 9:05
  • \$\begingroup\$ @XtremeBiker just use Struts 1 framework \$\endgroup\$ – Mercer Apr 29 '16 at 9:05
1
\$\begingroup\$

I would definitely try to migrate your DAO to a JPA compliant code. This way you don't have to manage the sessions yourself and you focus in CRUD operations. It would be enough setting up an entity manager factory at the time your DAO is created:

protected void setUp() throws Exception {
    entityManagerFactory = Persistence.createEntityManagerFactory( "org.hibernate.test.jpa" );
}

Then, for each operation you retrieve a specific EntityManager:

protected void save(Object o) {
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    entityManager.getTransaction().begin();
    entityManager.persist(o);
    entityManager.getTransaction().commit();
    entityManager.close();
}

This method might seem a bit more complex compared to your original save, but keep in mind you have Hibernate handling the session under the covers and you get rid from most of the management methods of your DAO.

Anyway you should be careful, the DAO layer closes the session was soon as operation finishes. If you are using lazy collection initializations however, you'll have to create specific methods to get it fully loaded from the DAO. As an example:

public Order loadOrderWithItems(){
    Order order = entityManager.find(Order.class, orderId);
    order.getItems().size();
}

As you make use of JPA 2.1 API, using EntityGraphs might be an interesting option too.

See also:

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.