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?

skaffman
  • 398,947
  • 96
  • 818
  • 769
EugeneP
  • 11,783
  • 32
  • 96
  • 142

3 Answers3

7

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
  • 138,234
  • 66
  • 282
  • 345
  • 2
    +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 Apr 02 '10 at 13:18
  • 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 Apr 02 '10 at 13:50
  • Oh, no harm done. I agree that it was important to explicitly say ;-) – Jeremy Apr 02 '10 at 14:30
4

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
  • 22,188
  • 4
  • 68
  • 81
  • @Jer Do DAO methods [in your case dao1] also have to have @Transactional attribute? – EugeneP Apr 02 '10 at 12:48
  • 1
    No. The DAOs will use the `SessionFactory.getCurrentSession()` to retrieve the `Session` scoped to the current transaction. – Jeremy Apr 02 '10 at 12:50
  • @Jer in your case dao1, dao2 are properties of the Service layer object? How do you inject them ? – EugeneP Apr 02 '10 at 12:52
  • Yes, they are. You can inject them by creating a spring `` element in your Spring configuration XML file. – Jeremy Apr 02 '10 at 12:56
  • @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 – leedm777 Apr 02 '10 at 13:11
  • 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 Apr 02 '10 at 13:42
  • @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 Apr 02 '10 at 13:50
2
  • 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
  • 588,226
  • 146
  • 1,060
  • 1,140
  • @Bozho Service layer - how does it extract DAO objects ? Using ApplicationContext as well? – EugeneP Apr 02 '10 at 12:57
  • 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 Apr 02 '10 at 13:09
  • @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 Apr 02 '10 at 13:23