DAO and Service layer in Spring: session management - java

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:
instantiate a DAO implementation object
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:
DAO object
Service layer methods, and class as a whole
so that it would give what is needed?

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.

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.

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.

Related

Transaction management in EJB 3.0 and hibernate

I am trying to understand the transactions management and try to use its power in my already existing application developed in Struts 2, EJB 3 and hibernate 5.2.
Now I have ejb in my business layer like below
#Stateless
#TransactionManagement(TransactionManagementType.CONTAINER)
public class MyEJb implements ejbxyz {
#Override
public void method(){
Dao dao=new Dao() //Dao class is simple java class
dao.fooMethod(); //this method updates some record
dao.barMethod(); // this method updates some other record
}
}
public class Dao{
fooMethid(){
Session session=sessFactory.openSession();
session.beginTransaction();
session.update(x);
}
barMethod(){
try{
Session session=sessFactory.getCurrentSession();
session.getNamedQuery("xyz").executeUpdate();
}catch(HibernateException ex){
session.getTransaction.rollback();
}
}
}
I understand that Transaction management should be done at service layer(at ejb in my case). But how can I achieve this over there. ?
Now the dependency is if barMethod() fails to update the record then I need to rollback the changes made in fooMethod. So basically I need both the methods to be done in one transaction.
When I execute the application it throws the below exception
Exception while barMethod getNamedQuery is not valid without active transaction
Its because I am not beginning any transaction in barMethod. But then I really dont want to start a new transaction and want to continue with the older transaction started in fooMethod.
Container managed transactions are indeed suported out of the box for EJB beans. However, your Dao class is not a managed bean - it is a regular pojo that you instantiate manualy - therefore it does not participate in any transaction started by your other ejb.
So move your Dao to separate file, annotate it with #Stateless and then inject it into your service using #EJB private Dao dao;
There is more to transactions in Ejb container though. You can control the transaction support on method level via #TransactionAttribute annotation, that specifies how should the container invoke your method with regard to transaction. That way you can control, whether your method requires its own transaction, or if it shall participate in a transaction initiated by the caller(e.g. when invoked from ejb bean). For more info have a look at official Java EE tutorial

Lazy loading working in non-transactional class/method in Hibernate

I am working in Spring-Hibernate application. Flow is as usual: Controller --> Service --> DAO.
I have annotated Service layer class with #Transactional, thereby marking every method transactional in that class.In service class, I made a DAO call to get some domain object and then converting it into DTO/VO object which will be passed to controller.For converting domain object to DTO, I have written another custom static class(class having only static methods) like ObjectMapper which will do this conversion.
Now, domain object has some child object(One to Many) which is lazily loaded. So, when in ObjectMapper, i access that child getter method, an extra database call is issued, which is working fine.
What I don't understand is that since ObjectMapper is not transactional, I was expecting some exception to be thrown like Session is closed while making database call to fetch child object from database.I am using getCurrentSession of Session Factory in DAO.
Can someone please explain me this behavior?
I suppose you either call your ObjectMapper from the transactional Service method (you should) or if not, maybe you are enabled "hibernate.enable_lazy_load_no_trans" which keeps the hibernate session open
As long as the call to the static class/method, which transforms your objects, is made in the transactional method of the DAO, the session is still open and will be used for the database calls.

#Transactional and Connection Leakage Spring Hibernate c3p0

In my application, i'm using
c3p0 as DataSource, which is passed to Hibernate session factory
transactionManager as HibernateTransactionManager
applicationConfig has tx:annotation-driven to detect #Transactional present in Service Methods and NOT in DAO methods.
ServiceImpl classes implement Service interface.
Service Methods call DAO methods.
DAO classes are Autowired in the ServiceImpl classes.
I have a DefaultDAOImpl to have common dao methods.
Other DAOImpl classes extend DefaultDAOImpl.
Service methods make single DAO call.
DAO methods make internal calls also, sometimes on the same DAOImpl and also on DefaultDAOImpl methods.
session is obtained using sessionFactory.getCurrentSession in DefaultDAOImpl as well as other DAOImpl methods.
session.close is NOT called from code.
Is there anything I am doing that might cause connection leak?
I am seeing c3p0 DeadLockDetector running from the logs.

DAO class instance vs DAO EJB

What is the best practice in java EE?
Create an instance of the DAO class in the service (or manager) class
SalesDAO salesDao = new SalesDAOImpl();
salesDao.findCustomers();
or
Call a DAO EJB in the service (or manager) class
#EJB
private SalesDAO salesDao;
salesDao.findCustomers();
The second one is the best practice (your DAO could be a CDI bean: it doesn't have to be an EJB).
Dependency injection is what makes the code testable: you can inject a mock DAO in the service when unit-testing the service.
BTW, the DAO will also need to have a DataSource or an EntityManager injected to be able to get data from the database. This is only possible if the DAO instance is managed by the container.
I preffer the second one.
DAO talks about responsability, means manage persistent data. But there is no reason for not to use a EJB. Let the container manage instances for you.
Adam Bien, member of EJB 3.1 spec comitee said in his blog:
http://www.adam-bien.com/roller/abien/entry/generic_crud_service_aka_dao

Is it okay to pass injected EntityManagers to EJB bean's helper classes and use it?

We have some JavaEE5 stateless EJB bean that passes the injected EntityManager to its helpers.
Is this safe? It has worked well until now, but I found out some Oracle document that states its implementation of EntityManager is thread-safe. Now I wonder whether the reason we did not have issues until now, was only because the implementation we were using happened to be thread-safe (we use Oracle).
#Stateless
class SomeBean {
#PersistenceContext
private EntityManager em;
private SomeHelper helper;
#PostConstruct
public void init(){
helper = new SomeHelper(em);
}
#Override
public void business(){
helper.doSomethingWithEm();
}
}
Actually it makes sense.. If EntityManager is thread-unsafe, a container would have to do
inercept business()
this.em = newEntityManager();
business();
which will not propagate to its helper classes.
If so, what is the best practice in this kind of a situation? Passing EntityManagerFactory instead of EntityManager?
EDIT: This question is very interesting so if you are interested in this question, you probably want to check out this one, too:
EDIT: More info.
ejb3.0 spec
4.7.11 Non-reentrant Instances
The container must ensure that only one
thread can be executing an instance at
any time. If a client request arrives
for an instance while the instance is
executing another request, the
container may throw the
javax.ejb.ConcurrentAccessException to
the second client[24]. If the EJB 2.1
client view is used, the container may
throw the java.rmi.RemoteException to
the second request if the client is a
remote client, or the
javax.ejb.EJBException if the client
is a local client.[25] Note that a
session object is intended to support
only a single client. Therefore, it
would be an application error if two
clients attempted to invoke the same
session object. One implication of
this rule is that an application
cannot make loopback calls to a
session bean instance.
And,
4.3.2 Dependency Injection
A session bean may use dependency injection
mechanisms to acquire references to
resources or other objects in its
environment (see Chapter 16,
“Enterprise Bean Environment”). If a
session bean makes use of dependency
injection, the container injects these
references after the bean instance is
created, and before any business
methods are invoked on the bean
instance. If a dependency on the
SessionContext is declared, or if the
bean class implements the optional
SessionBean interface (see Section
4.3.5), the SessionContext is also injected at this time. If dependency
injection fails, the bean instance is
discarded. Under the EJB 3.0 API, the
bean class may acquire the
SessionContext interface through
dependency injection without having to
implement the SessionBean interface.
In this case, the Resource annotation
(or resource-env-ref deployment
descriptor element) is used to denote
the bean’s dependency on the
SessionContext. See Chapter 16,
“Enterprise Bean Environment”.
I used a similar pattern, but the helper was created in #PostConstruct and the injected entity manager was passed in the constructor as parameter. Each EJB instance had its own helper and thread-safety was guaranteed then.
I also had a variant were the entity manager was not injected (because the EJB wasn't using it altogether), so the helper has to look it up with InitialContext. In this case, the Persistence context must still be "imported" in the parent EJB with #PersistenceContext:
#Stateless
#PersistenceContext(name="OrderEM")
public class MySessionBean implements MyInterface {
#Resource SessionContext ctx;
public void doSomething() {
EntityManager em = (EntityManager)ctx.lookup("OrderEM");
...
}
}
But it's actually easier to inject it (even if the EJB doesn't use it) than to look it up, especially for testability.
But to come back to your main question, I think that the entity manager that is injected or looked up is a wrapper that forwards to the underlying active entity manager that is bound to the transaction.
Hope it helps.
EDIT
The section § 3.3 and § 5.6 in the spec cover a bit the topic.
I've been using helper methods and passed the EntityManager there, and it is perfectly OK.
So I'd recommend either passing it to methods whenever needed, or make the helper a bean itself, inject it (using #EJB) and inject the EntityManager there as well.
Well, personally, I wouldn't like to have to pass the Entity Manager to all my POJOs in my constructors or methods. Especially for non-trivial programs where the number of POJOs is large.
I would try to create POJOs/HelperClasses that deal with the Entities returned by the EntityManager, instead of using the entitymanager directly.
If not possible, I guess I'd create a New EJB Bean.

Categories