views:

672

answers:

3

Am I right in understanding the principles of DAO & Service layer interconnection? DAO performs extractions of base objects, say by id from a db.

Service layer USES a DAO object and may invoke MORE THAN ONE METHOD of DAO in one function. So, Service layer has to:

  1. instantiate a DAO implementation object

  2. invoke as many methods of the DAO as needed

If a Dao implements an interface, then does a DAO interface has to have a method setSessionFactory()?

How to declaratively mark in Spring:

  1. DAO object

  2. Service layer methods, and class as a whole

so that it would give what is needed?

+4  A: 

For my projects I write a base class which has a setSessionFactory() method that all my DAOs extend. Then I wire up my DAOs with Spring so that it injects the SessionFactory into each DAO.

Hibernate has a SessionFactory.getCurrentSession() so if you inject the SessionFactory into your DAOs and use that method, then the scope of the Session will be defined according to your transaction management mechanism.

What this means is if you have a method as such:

@Transactional
public void doSomething(){
    dao1.makeCall();
    dao2.makeOtherCall();
}

The SessionFactory you inject into each DAO when constructed will be using the same Session. But only for the scope of that transaction.

Jeremy
@Jer Do DAO methods [in your case dao1] also have to have @Transactional attribute?
EugeneP
No. The DAOs will use the `SessionFactory.getCurrentSession()` to retrieve the `Session` scoped to the current transaction.
Jeremy
@Jer in your case dao1, dao2 are properties of the Service layer object? How do you inject them ?
EugeneP
Yes, they are. You can inject them by creating a spring `<bean>` element in your Spring configuration XML file.
Jeremy
@EugeneP - Usually you mark your service classes and service methods with the `@Transactional annotation`. If you get lazy initialization exceptions serializing objects, look at the `OpenSessionInViewFilter` for keeping the transaction open for the entire web request. http://static.springsource.org/spring/docs/3.0.x/api/org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.html
dave
if all I need is a complex structure, let's say a combination of different tables with join fetch I must only add a new method to DAO and not use a Service layer?
EugeneP
@Eugene- It really depends on what you need. If you need data from a couple DAOs and it makes sense to wrap all that into a single transaction, then you would write a service method that would call the methods on the DAOs. You *could* put `@Transactional` on a DAO method if you're going to skip the service layer. I don't think it will harm any other transaction since opening a transaction inside of another transaction has no effect. That is, a second transaction does not open.
Jeremy
+2  A: 
  • Leave transaction and session management to spring (via the built-in transaction managers).
  • In your DAOs use sessionFactory.getCurrentSession() tp access the session
  • have the SessionFactory injected in the DAO.
  • have DAO in scope singleton
  • use declarative transactions (either with <aop or with @Transactional)
  • the DAO is injected into the service objects via a regular dependency-injection. The same way the service classes are injected where they are needed.
Bozho
@Bozho Service layer - how does it extract DAO objects ? Using ApplicationContext as well?
EugeneP
Also, about singleton, that's the same question. If it is gotten from Spring then it will be singleton, if not then explain what you mean.
EugeneP
@Eugene- Spring-constructed objects are by default singletons (mostly) but the `SessionFactory.getCurrentSession()` method only returns a *new* `Session` the first time it is called in the scope of the transaction. Otherwise it will continue returning the same `Session` until the transaction is over, regardless of which class obtained the `Session`.
Jeremy
@Bozho Best answer +1
c0mrade
+5  A: 

I'm surprised no one else has specifically mentioned this, but an implementation-specific detail such as setSessionFactory() should not be in your DAO interface. By adding a Hibernate-specific class to your DAO interface, you are tying your DAO's directly to Hibernate.

The purpose of using interfaces and dependency injection is to allow you to change an implementation detail (such as, what ORM solution you use, or if your data comes from a web service vs a database) of a layer (your DAO) without affecting other layers.

If you add setSessionFactory to your DAO interface, then all other layers that use this DAO become aware and tied to the fact that the data access is done through Hibernate. This is the direct opposite of what you are trying to achieve by using interfaces and dependency injection.

matt b
@matt b very helpful!
EugeneP
+1 I implied this, but it's good that you said it. A DAO of mine usually ends up looking like this `class UserHibernateDAO extends HibernateDAO implements UserDAO` where `HibernateDAO` is an abstract class. Then if I ever need a `FileDAO` I can just swap out the boiler plate.
Jeremy
Agreed that it was implied but I think it's important to call out. I edited the word "specifically" into "nobody mentioned this", I realize it was just implied :)
matt b
@matt- Oh, no harm done. I agree that it was important to explicitly say ;-)
Jeremy