views:

108

answers:

2

I've been reading about the sun blueprint GenericDAO implementation and Gavin King's take on this for use with Hibernate. It seems he doesn't mention anything about transaction handling:

public abstract class GenericHibernateDAO<T, ID extends Serializable> {
    protected Session getSession() {
        return HibernateUtil.getSessionFactory().getCurrentSession();
    }

    public T makePersistent(T entity) {
        getSession().saveOrUpdate(entity);
        return entity;
    }
}

I'm puzzled as to where I should put the start/end of the transaction. Currently they are inside the DAOs that extend this GenericHibernateDAO

public class FooHibernateDAO extends GenericHibernateDAO<Foo, Long> {
    public Foo saveFoo(Foo foo) {
        getSession().beginTransaction();
        makePersistent(foo);
        getSession().getTransaction().commit();
    }
}

Should the transaction handling be managed by the caller of the DAO in the application tier?

+10  A: 

Generally the best practice is to manage transactions in service layer not in DAO layer. Each DAO method generally handles one specific operation and a service method aggregates them in one transaction.

Teja Kantamneni
That's it +1 - you beat me to it
Romain Hippeau
+3  A: 

Transactions should be managed in the application tier. Say for example you had an AccountDAO:

public class AccountDAO {
   public void DebitAccount( int accountId, int dollars ) {

   }

   public void CreditAccount( int accountId, int dollars ) {
   }
}

If I wanted to transfer money between accounts, I would call DebitAccount on one account and CreditAccount on another. I would want these calls to happen in the same transaction. The DAO can't possibly know that, but the application tier would.

If transactions were managed at the DAO tier, you would need to create another TransferMoney method on the DAO to do it in one transaction. This would eventually bloat your DAO tier and, for complex operations, bring in business logic that probably shouldn't be there. And it gets even messier if you have an operation that requires multiple DAOs to be involved in a single transaction.

Eric Petroelje
so take an example like a loan system where lots of queries are done in order to decide on a quote, then the quote is written to the DB, would you start the transaction before all the reads? Also the `GenericDao` has no public method to retrieve the Session in order to start the transaction?
James
@James - I would start the transaction before any writes occur, but not necessarily before the reads. And yes, there would be no need for the DAOs to worry about transactions, so no method is needed. The transactions would be managed in the service layer.
Eric Petroelje
Ok thanks for that. One last thing if you don't mind - the service layer starts the transaction but in order for it to do this it needs access to a 'Session' in order to call `session.beginTransaction()`. If it's not the DAO that provides the service layer with the `Session`, where does it come from? the static `SessionFactory`?
James
Also, going back to the loan example, should all the reads be in a single transaction or separate ones for each read?
James
@James - Regarding the first comment, yes, I think having the service layer get it from the session factory would be fine. Regarding your second question, reads do not change anything, so they don't need to be part of a transaction. You can't "commit" or "rollback" a read, so no need to introduce transactions at all for read-only operations.
Eric Petroelje
Assuming the system has the hibernate default read-committed isolation level, code that makes a financial decision seems like a textbook case for putting the reads inside the same transaction with elevated isolation, no?
Affe
@Affe - yes, if you are doing reads mixed in with writes in your service layer and need to be able to re-read data that has not yet been committed. Typically I don't think you would need to do that as you normally do your reads first followed by writes, but that would be a case-by-case decision that you would make in your service layer.
Eric Petroelje
I would be more concerned withAllison reads table A, Jim updates Tables A and B, Allison reads table B, Allison issues loan quote based on inconsistent combination of data from A and B. Anyway, this is probably well out of scope for the comment thread, just thought OP should keep in mind that he is working in Read-Committed by default and be aware of what that means. optimistic locking may or may not protect him depending on what the relationships are.
Affe