8

I have many Tables, For every Table,we have DAO Interface and DAOImplementation class.

Example DAO Interface

public interface CancelPolicyDAO {

public CancelPolicy insertCancelPolicy(CancelPolicy cpdao)throws ChannelDispatcherException;

public CancelPolicy updateCancelPolicy(CancelPolicy cpdao)throws ChannelDispatcherException;

public void deleteCancelPolicy(CancelPolicy cpdao)throws ChannelDispatcherException;

public CancelPolicy findByCancelPolicyData(Integer id, Integer offSetUM, Integer nights, Float pOrAm, Byte isPercent)throws ChannelDispatcherException;

public CancelPolicy findByCancelPolicyId(Integer id)throws ChannelDispatcherException;
}

Example DAOImplementation class

public class CancelPolicyDAOImpl implements CancelPolicyDAO {

@Override
public CancelPolicy insertCancelPolicy(CancelPolicy bean) throws ChannelDispatcherException {

    Session ses = null;
    try {

        ses = HibernateConnector.getInstance().getSession();
        ses.save(bean);
        ses.flush();
        return bean;
    } catch (Exception e) {
        e.printStackTrace();
        throw new ChannelDispatcherException(DbUtil.getStackTraceMessage(e));
    } finally {
        if (ses != null) {
            try {
                ses.close();
            } catch (Exception er) {
                er.printStackTrace();
            }
        }
    }

}

@Override
public CancelPolicy updateCancelPolicy(CancelPolicy bean) throws ChannelDispatcherException {
    Session sess = null;

    try {

        sess = HibernateConnector.getInstance().getSession();
        sess.update(bean);
        sess.flush();
        return bean;
    } catch (Exception e) {
      e.printStackTrace();
        throw new ChannelDispatcherException(DbUtil.getStackTraceMessage(e));
    }

}

@Override
public void deleteCancelPolicy(CancelPolicy bean) throws ChannelDispatcherException {
    Session sess = null;

    try {

        sess = HibernateConnector.getInstance().getSession();
        sess.delete(bean);
        sess.flush();
    } catch (Exception e) {
     e.printStackTrace();
        throw new ChannelDispatcherException(DbUtil.getStackTraceMessage(e));
    }

}

@Override
public CancelPolicy findByCancelPolicyData(Integer id, Integer offSetUM, Integer nights, Float pOrAm, Byte isPercent) throws ChannelDispatcherException {

    Session ses = null;
    try {
        ses = HibernateConnector.getInstance().getSession();
        Query query = ses.createQuery("from CancelPolicy a where "
                + " a.cancelPolicyTypeId =:cancelPolicyTypeId  "
                + " and   a.offsetUnitMultiplier =:offsetUnitMultiplier  "
                + " and   a.nights =:nights  "
                + " and   a.percentOramount =:percentOramount "
                + " and   a.isPercent =:isPercent");

        query.setParameter("cancelPolicyTypeId", id);
        query.setParameter("offsetUnitMultiplier", (offSetUM));
        query.setParameter("nights", (nights));
        query.setParameter("percentOramount", pOrAm);
        query.setParameter("isPercent", isPercent);

        List queryList = query.list();
        if (queryList != null && queryList.isEmpty()) {
            return null;
        } else {
            return (CancelPolicy) queryList.get(0);
        }
    } catch (Exception e) {
       e.printStackTrace();
        throw new ChannelDispatcherException(DbUtil.getStackTraceMessage(e));
    } finally {
        if (ses != null) {
            try {
                ses.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

public CancelPolicy findByCancelPolicyId(Integer id) throws ChannelDispatcherException {

    Session ses = null;
    try {
        ses = HibernateConnector.getInstance().getSession();
        Query query = ses.createQuery("from CancelPolicy a where "
                + " a.id =:id  ");

        query.setParameter("id", id);

        List queryList = query.list();
        if (queryList != null && queryList.isEmpty()) {
            return null;
        } else {
            return (CancelPolicy) queryList.get(0);
        }
    } catch ( Exception e) {
       e.printStackTrace();
        throw new ChannelDispatcherException(DbUtil.getStackTraceMessage(e));
    } finally {
        if (ses != null) {
            try {
                ses.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}  

Example main method

 public static void main(String[] args)  {

       // How to handel Transaction in Hibernate ?
     CancelPolicyDAO cancelPolicyDAO = HibernateDAOFactory.getInstance().getCancelPolicyDAO();


     CancelPolicy insertCancelPolicy = cancelPolicyDAO.findByCancelPolicyData(2, 76, 25, 25.36f, 3);
    if(insertCancelPolicy==null){
        CancelPolicy cancelPolicy = new CancelPolicy();
    cancelPolicy.setCancelPolicyTypeId(1);
    cancelPolicy.setNights(2);
     insertCancelPolicy = cancelPolicyDAO.insertCancelPolicy(cancelPolicy);
    }
    Integer autoIncrementId = insertCancelPolicy.getId();

    AvailabilityDAO availabilityDAO =  HibernateDAOFactory.getInstance().getAvailabilityDAO();
    Availability availability = new Availability();
//        using  CancelPolicy autoIncrementId 
    availability.setId(autoIncrementId);
    availability.setCount(2);
    availability.setMaxLos(5);
    availabilityDAO.insertAvailability(availability);
    .
    .
    .
    .
    .


 }

Now my question is how do i handle Transaction in DAOImpl's ? Should i pass Session Object as parameter for every DAOImpl's or is there is any better Approach

LMK
  • 2,882
  • 5
  • 28
  • 52
  • 1
    Use AOP based TX management and delete 80% of your code. – Pavel Horal Nov 27 '14 at 11:55
  • Are you using the Spring framework ? If so take a look at this : http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/transaction.html – Anarki Nov 27 '14 at 11:56
  • @Anarki no im using only Jse(core java) – LMK Nov 27 '14 at 11:57
  • I agree with Pavel Horal, your code will became more cleaner and readable – Anarki Nov 27 '14 at 12:01
  • @PavelHoral i have googled it , but i guess it is related to springs.but i am not using springs , i use only jse(core java) – LMK Nov 27 '14 at 12:03
  • 1
    You can implement it yourself... I think that a good starting point would be to replicate [`TransactionTemplate`](http://docs.spring.io/spring-framework/docs/2.0.8/api/org/springframework/transaction/support/TransactionTemplate.html) logic - i.e. component which is capable of executing a callback (e.g. `Callable`) inside an active transaction / persistence session. This means starting the transaction (creating `Session`) before calling the callback and finishing transaction (flushing `Session`, committing or rollbacking in case of exception) after calling the callback. – Pavel Horal Nov 27 '14 at 12:07
  • Main objective is to get rid of the repeated unnecessary `try/catch/finally`, rollback logic, flushing... – Pavel Horal Nov 27 '14 at 12:09
  • @PavelHoral correct me if i am wrong , so you are suggesting me to create session object at starting line of main method and pass it as parameter in all DAOImplementation's ? so if exception occoured rollback in main method catch block ? else commit – LMK Nov 27 '14 at 12:17
  • Passing session object -> definitely not! Active session is accessible via [`SessionFactory`](http://docs.jboss.org/hibernate/orm/3.5/javadocs/org/hibernate/SessionFactory.html#getCurrentSession%28%29). There is no need to pass this object around. – Pavel Horal Nov 27 '14 at 12:28
  • @PavelHoral so you are suggesting me to create transaction object at starting line of main method and access via SessionFactory in DAOImpl , so if exception occoured rollback in main method catch block ? else commit – LMK Nov 27 '14 at 12:33
  • 1
    Well not exactly, but that would be a good start. As I said - the main objective is to get rid of the unnecessary duplicated logic in your DAO methods. – Pavel Horal Nov 27 '14 at 12:36

4 Answers4

11

While using Spring is probably the best way to add transaction management, you can still work it out even without re-factoring all your code-base.

What you need to do is to set the following configuration:

hibernate.current_session_context_class=thread

You DAOs should access the Session through:

[SessionFactory.getCurrentSession()][1];

You still need to declare transaction boundaries in your Service layer:

Session sess = factory.openSession();
Transaction tx = null;
try {
    tx = sess.beginTransaction();

    dao1.find();
    dao2.save(entity);

    tx.commit();
}
catch (RuntimeException e) {
    if (tx != null) tx.rollback();
    throw e;
}
finally {
    sess.close();
}

Both the DAO1 and DAO2 will use the same Hibernate Session and the same Transaction.

To avoid this verbose transaction management code handling you can write a simple TransactionManager utility such as:

public static abstract class TransactionCallable<T> {
    public abstract T execute();
}

public class TransactionManager {   
    public static <T> T doInTransaction(TransactionCallable<T> callable) {
        T result = null;
        Session session = null;
        Transaction txn = null;
        try {
            session = sf.openSession();
            txn = session.beginTransaction();

            result = callable.execute();
            txn.commit();
        } catch (RuntimeException e) {
            if ( txn != null && txn.isActive() ) txn.rollback();
            throw e;
        } finally {
            if (session != null) {
                session.close();
            }
        }
        return result;
    }
}

And this is how a service will look like:

TransactionManager.doInTransaction(new TransactionCallable<Void>() {
    @Override
    public Void execute() {
        dao1.find();
        dao2.save(entity);
    }
});
Patrick
  • 1,717
  • 7
  • 21
  • 28
Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
  • Pretty nice. I was actually looking for something like this. While everyone keeps saying Spring is the one and only way to go, for existing code these kinds of implementations work, with the added benefit of not needing to add all the bulk of additional dependencies. – ibelcomputing Apr 23 '15 at 21:47
  • Where is SessionFactory instance? – Eldar Agalarov Dec 31 '20 at 20:57
10

I'd strongly recommend not to reinvent the wheel; use existing, robust and tested code.

The comments already mentioned AOP and the Spring framework. This is imho the way to go. The Spring framework even has a subproject called Spring Data that allows you to define your finder methods (like findByCancelPolicyData) in a declarative way.

This will save you a lot of work.

If for any reason you don't want to / may not use Spring, you can still read the amazingly good documentation of the base framework and the mentioned Spring Data in order to gain lots of excellent ideas, regarding transaction (via AOP), code reuse (via generic DAOs) or API design. Don't miss this read.

Hille
  • 4,096
  • 2
  • 22
  • 32
2

If you have web application and you are not using spring in your project for session mgmt, I would suggest to use interceptor to separate the session handling logic outside of your DAO. You can refer below mentioned article for the same. Note that there are certain CONs associated with this approach but we have found it to be the most convenient way in our case.

Open Session in View Pattern

Below is the example of how we are using Open Session in View pattern with Generics, for your class we can have,

   public class CancelPolicyDAOImpl extends GenericDAOImpl<CancelPolicy, Long> implements CancelPolicyDAO {

   @Override
public CancelPolicy insertCancelPolicy(CancelPolicy bean) throws ChannelDispatcherException {


        try {
          // save method is implemented in GenericDAOImpl described below.
           return save(bean);
        } catch (Exception e) {
            e.printStackTrace();
        } 

        }
//remaining methods
}

In above code save method is used which is implemented in GenericHibernateDAOImpl as shown below. You can Google for GenericHibernateDAOImpl class and grab it which has number of additional methods for basic operations.

public abstract class GenericDAOImpl<T, ID extends Serializable>  {

    private Session session;

 public T save(final T entity) {
        Transaction trans = null;
        try {
            trans = session.beginTransaction();
            session.saveOrUpdate(entity);
            session.flush();
            trans.commit();
        } catch (Exception ex) {
            rollBackTransaction(trans);
// you might require to throw error again here
        }
        return entity;
    }

//in case any complex operations required you can get core session object from this method
    protected Session getSession() {
        return sessionFactory.getCurrentSession();
    }
}

Now back to your question about where to get the session, as shown above GenericHibernateDAOImpl session is retrieved from singleton sessionFactory through getCurrentSession method. Note that you will require to have active transaction running before getting current session which you can make available in your interceptor (link provided in the beginning of this post).

Please let me know.

Sariq Shaikh
  • 940
  • 8
  • 29
0

No need to use frameworks, the CancelPolicy object is the main object and it should has hibernate feature (cascade) Check the Link (Cascading life cycle)

So you fill the CancelPolicy object with all required relations, and say save, it will save all the graph of the related objects.

Bassel Kh
  • 1,941
  • 1
  • 19
  • 30