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.
Related
When using Hibernate and JPA, I have an existing DAO Abstract Class that sets up an entity manager this way:
#PersistenceContext(unitName = "<name>")
private EntityManager entityManager;
And in certain methods, it's used in the following manner:
public ObjectType findByPrimaryKey(int id) {
return entityManager.find(ObjectType, id);
}
I wanted to set a database configuration parameter in the same transaction as the "find" query. However, I can't seem to find the internal transaction that entityManager uses. I wrote an Aspect that checks for Transactional annotation and sets the variable in there, and added #Transactional on top of findByPrimaryKey method, but that still didn't get set in the session.
Is there something incorrect here or another way to do it? Ideally, want to set a special variable before every query.
Final solution was to combine Spring's "#Transactional" annotation, which automatically opens a transaction, before calling my Data access layer, with an Aspect that pointcuts to "#Transactional" annotation and runs queries within a transaction. Just executing any query within an "#Transactional" method will also work, before calling the Hibernate data access layer.
Without the "#Transactional" annotation, I couldn't control Hibernate's transaction management.
I've got an entity class and few services. That works well. But now I want to use a service inside an entity. I've added #Configurable and #Transient annotation to entity class and also <context:spring-configured /> statement to root-context.xml. Console says:
java.lang.NullPointerException
I've checked if service field is null and yes, it is. What is wrong?
Entities are not Spring beans. Spring doesn't know about them, and is not responsible for their instantiation. It thus can't inject anything into them.
Calling a service from an entity is just not something you should do. The service layer uses the domain layer, but not vice-versa.
I created a bean instance with
Type instance = new Type();
and autowired it using
ctx.getAutowireCapableBeanFactory().autowireBean(instance);
The beans run method is executed by a ThreadPoolTaskExecuter and is annotated with the
#Transactional annotation which has no effect in this case. Since lazy loading problems occur. I need a transaction here.
How can I create a transactional proxy and wrap my instance?
Is there a way other than using transaction-manager manually?
You should get the correct proxy if you apply BeanPostProcessors from the context:
instance = ctx.getAutowireCapableBeanFactory().applyBeanPostProcessorsAfterInitialization(instance);
You can certainly create a PlatformTransactionManager subclass manually and use its methods to create and commit or rollback transactions.
If you want to proxy an object, the class you probably want is org.springframework.transaction.interceptor.TransactionProxyFactoryBean. Setup an instance of that and call getObject() to get your proxied class.
I have a Transaction problem on Spring 3.0.5. In my case I get the so-called exception "No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here"... I have tried everything so far. I can see in my log that the transactional services are detected and registered as Spring beans and I can also see in the logs that they are proxied and associated with underlying Spring transaction interceptors. (Advise) When I run my Spring MVC app my controller will call the service...... :-( but the transaction interceptors are not triggered. (??) I expect my Spring service proxy to open a session and start a transaction before calling my target service method. Since this does not happen, I get the above exception. I have been almost two days on this problem. Tried everything which I found on the internet...but in vain.
I have layered architecture: presentation (springmvc), service (transaction annotated), dataacess (Spring/Hibernate classic sessionfactory). My model objects are annotated with jpa (javax.persistence.*). My spring context config files are separated in appContext.xml, appContext-service.xml and appContext-dao.xml. I have defined my Spring LocalSessionFactoryBean, Datasource and TransactionManager (HibernateTransactionManager) in appContext-dao.xml. I have put in appContext-service.xml where my service implementations resides. In all of my config files I have included and to detect my beans through Controller, Service and Repository annotations.
I appreciate any kind of help.
It sounds like you are doing everything correctly and you know what you are doing. There's not much we can do here unless you show some configuration.
What I'd suggest is some debugging.
First: do you have Unit tests in the service layer that test the queries you are using? Perhaps you can find the error in the service layer.
Then: debug the MVC app, check the types of the injected services. Verify that they are proxies, not the original types.
If they are the original types, you
have an error in your transaction
configuration .
If they are proxies, step through the
query methods and verify that the
transaction logic is applied.
This sounds like accessing a lazily-loaded list or set of you dao after the closing of the transaction. This typically happens if you access that list in the view in stead of the controller, as your controller probably calls methods in transaction scope, and then leaves the transaction and forwards the loaded bean to the view.
Simple solutions:
Configure your data bean to eagerly load
Force loading of the dependencies in the controller (just loop through them)
have a look at this article ans possibly also quite a few right here on SO on lazy loading / lazy fetching of one-to-many associations and the like
Imagine:
// your dao
public class Foo {
// lots of other properties
List<Something> stuff;
// getters and setter for stuff
}
// repository
#Transactional
public class FooRepo {
public Foo loadFoo(int id) {
...
}
}
// Controller
public class Controller {
public void Control() {
sessionContext.set("foo", repo.loadFoo(1)); // transaction managed by spring
}
public void setFooRepo(FooRepo repo) {this.repo = repo};
}
// View
for (Something something : foo.getStuff()) {
// Ooops transaction is closed! stuff is lazily loaded so NOT AVAILABLE
// practical solutions:
// - do not load lazily (Foo.hbm.xml)
// - or force loading by getting all Somethings in the controller
}
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.