Lazy-loading with Spring HibernateDaoSupport? - java

Greetings I am developing a non-webapplication using Spring+Hibernate.
My question is how the HibernateDaoSupport handles lazy-loading , because after a call do DAO , the Session is closed.
Take a look at following psuedo-code:
DAO is like:
CommonDao extends HibernateDaoSupport{
Family getFamilyById(String id);
SubFamily getSubFamily(String familyid,String subfamilyid);
}
Domain model is like:
Family{
private List<SubFamily> subfamiles;
public List<SubFamily> getSubFamiles();
}
SubFamily{
private Family family;
public Family getFamily();
}
In the application I get DAO from app-context and want to following operations.Is this possible to do with lazy-loading because AFAIK after every method (getFamilyById() , getSubFamily() ) the session is closed.
CommonDAO dao=//get bean from application context;
Family famA=dao.getFamilyById(familyid);
//
//Do some stuff
List<SubFamily> childrenA=fam.getSubFamiles();
SubFamily asubfamily=dao.getSubFamily(id,subfamilyid);
//
//Do some other stuff
Family famB=asubfamily.getFamily();

My question is how the HibernateDaoSupport handles lazy-loading , because after a call to DAO, the Session is closed.
The DAOs don't create/close a Session for each call, they are not responsible for this and this is usually done using the "Open Session in View" pattern (Spring provide a filter or an interceptor for this). But this is for web apps.
In a swing app, one solution is to use long session. You'll have to decide well-defined points at which to close the session to release memory. For small applications, this is usually straightforward and will work. For bigger (i.e. real life apps), the right solution is to use one session per frame/internal frame/dialog. It's harder to manage but will scale.
Some threads you might want to read:
hibernate LazyInitializationException in rich client app
Spring/Hibernate long session support or best practice?
Keep hibernate session open in swing client? (this one is IMHO the most interesting, especially #9)
And the Hibernate and Swing demo app

If you are already using Spring you can make use of its Transaction-Declaration. Using this you are able to declare a transaction for a specific method. This keeps the Sessio open for the complete tx.
Declare the Transaction Pointcut
<!-- this is the service object that we want to make transactional -->
<bean id="SomeService" class="x.y.service.SomeService"/>
<tx:advice id="txAdvice" transaction-manager="txManager">
<!-- the transactional semantics... -->
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true"/>
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- ensure that the above transactional advice runs for any execution
of an operation defined by the FooService interface -->
<aop:config>
<aop:pointcut id="MyServicePointcut" expression="execution(* x.y.service.SomeService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="SomeServiceOperation"/>
</aop:config>
<bean id="txManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
Now you can do this lazy keeping the Session open for the complete Method.
public class SomeService()
{
public Family getFamily()
{
Family famA=dao.getFamilyById(familyid);
//Do some stuff
List<SubFamily> childrenA=fam.getSubFamiles();
SubFamily asubfamily=dao.getSubFamily(id,subfamilyid);
//Do some other stuff
return asubfamily.getFamily();
}
}
See Chapter 9 of Springs Tx Reference for further details.

Related

AOP advice on methods other than execute method of spring batch tasklet not being applied

This issue has started after migrating from spring 4.1.2 to 5.0.5, spring batch to 3.0.9 to 4.0.1 and hibernate 4.2.0 to 5.2.16
I have a spring batch tasklet of the format -
public class MyTasklet implements Tasklet {
public RepeatStatus execute(StepContribution arg0, ChunkContext arg1) {
a();
}
public void a(){
//a few hibernate calls here
}
}
Now I want my hibernate transaction boundary to be the method a() [being called from execute] and not the execute() method.
But when I try applying point-cuts to achieve the same I get a message "no transaction in progress". I have provided the sample xml below.
In the aop pointcut -instead of the method name 'a'[i.e public * myPackage.MyTasklet.a(..)], if I use * (i.e public * myPackage.MyTasklet.*(..)] or 'execute'[i.e public * myPackage.MyTasklet.execute(..)] the code works fine. Due to some technical reasons it is important to have the boundary at 'a' due to which I cannot have 'execute' or any other method as the boundary.
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="mySessionFactory" />
</bean>
<aop:config>
<aop:pointcut id="Op1"
expression="execution(public * myPackage.MyTasklet.a(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="Op1" />
</aop:config>
This question has been asked hundreds of times here. Your method a() is called internally, but internal method calls are never intercepted by Spring AOP because in that case you actually call this.a(). This does not go through the wrapping dynamic proxy used by Spring AOP. If a() was called from outside, e.e. by another component, it would work. This behaviour is comprehensively documented in the Spring AOP manual.
If you want to intercept internal method calls you have to use AspectJ instead of Spring AOP. How to configure Spring for AspectJ and LTW (load-time weaving) is also documented in the Spring manual.
P.S.: This is completely unrelated to your version upgrades. In older Spring and Spring Batch versions it would be the same. You mixed refactoring (version upgrade) with functional changes, which you should never do. Too many moving targets for debugging. Refactoring means to change the code (or the configuration, in this case) without changing its functionality.

Spring HibernateDaoSupport creates multiple sessions

I am using Struts2.3 + Spring 3.2.6 + Hibernate 3.X for my web application.
I am using annotations to manage the transaction.
My DAO class is as below.
#Transactional(readOnly = true, rollbackFor={Exception.class})
public class CustomerDAOImpl extends HibernateDaoSupport implements CustomerDAO{
//adds the customer
#Transactional(propagation=Propagation.REQUIRED, rollbackFor = {Exception.class})
public void addCustomer(Customer customer){
Session session = getSession();
System.out.println("M1() Hash Code: --->"+session.hashCode()+ " Thread id: "+Thread.currentThread().getId());
//session.save(customer);
}
//return all the customers in list
// #Transactional(propagation=Propagation.REQUIRED, rollbackFor = {Exception.class})
#Transactional(readOnly = true)
public List<Customer> listCustomer(){
Session session = getSession();
System.out.println("M2() Hash Code: --->"+session.hashCode()+ " Thread id: "+Thread.currentThread().getId());
return null; //logic to get the list based on condition
}
These methods will be called from service layer and it is like below;
customerDAO.addCustomer(customer);
customerDAO.listCustomer();
I am getting different sessions for same thread when the above code is executed.
Output:
M1() Hash Code: --->5026724 Thread id: 21
M2() Hash Code: --->8899550 Thread id: 21
Due to this, if any exception comes in method2() the data which is persisted using method1() is not rollback.
Please let me know, how to get the single session based on thread (if i go for my own HibernateFactory i lose transaction management by Spring) with out loosing spring transaction management.
If you are using Hibernate make your DAO class to extend HibernateDaoSupport. Now you can get session from getHibernateTemplate() method. That way you can have the session managed by spring-hibernate
You can try this -
appContext.xml
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="submit*" propagation="REQUIRED" read-only="false" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="appControllerTransactionPointCuts"
expression="execution(* com.test.customer.bo.Custom.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="appControllerTransactionPointCuts" />
</aop:config>
Remove -
<tx:annotation-driven transaction-manager="transactionManager" />
from appcontext.xml
Now AOP should manage transactions.
How Transactions work -
Suppose you are persisting objects in multiple DAO methods and you want them all to happen in one transaction, then you have to apply transaction at the service layer method where the DAO methods are getting called. For e., in my case the service layer is com.test.customer.bo.Custom.*
If you are not doing so, then each of your DAO method will be executed in a separate transaction and will get persisted to database if no exception occurs. If exception occur in method2() of DAO layer it will not rollback method1() as it is already committed.

Spring Transaction Management: using #Transactional vs using AOP (<aop:advisor)

I have a confusion about Spring transaction management. In my application I implemented transaction management using #Transactional in the service class. And I configured my spring.xml is like:
<beans:bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<beans:property name="dataSource" ref="dataSource" />
<beans:property name="configLocation" value="classpath:hibernate.cfg.xml"/>
<beans:property name="hibernateProperties">
<beans:props>
<beans:prop key="hibernate.dialect">${jdbc.dialect}</beans:prop>
<beans:prop key="hibernate.show_sql">false</beans:prop>
<beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
<!-- Transaction manager -->
<beans:bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<beans:property name="sessionFactory" ref="sessionFactory" />
</beans:bean>
If I implement transaction management in the configuration file like below without using #Transactional in the service class:
<aop:pointcut id="defaultServiceOperation"
expression="execution(* x.y.service.*Service.*(..))"/>
<aop:pointcut id="noTxServiceOperation"
expression="execution(* x.y.service.ddl.DefaultDdlManager.*(..))"/>
<aop:advisor pointcut-ref="defaultServiceOperation" advice-ref="defaultTxAdvice"/>
<aop:advisor pointcut-ref="noTxServiceOperation" advice-ref="noTxAdvice"/>
</aop:config>
does it give me any benefits over #Transactional? Someone told me using #Transactional is also implementation of AOP in spring. Can anyone explain me how?
It won't.
Benefits
If you don't need some very specified requirements or you have no performance issues, you shouldn't reinvent the wheel. Spring is almost perfectly designed, tested and sharped instrument, which can be replacement even for enterprise application servers. #Transactional is declarative way for managing transactions, it's far more convenient and readable than any aop xml configs. It's benefits include automatic handling of all transaction management aspects in declarative way: isolation and propagation levels (it's not easy to control nested transactions), timeouts, rollback conditions and distinct TransactionManagers for every single method of your service's class. Easy to read, easy to configure, easy to use.
#Transactional(readOnly = false, rollbackFor = ServiceException.class, isolation = Isolation.READ_COMMITTED)
public void myServiceJob(...)
When you see this method, it's easy to understand it's transactional attributes (without providing transactions implementation details in method). In case of plain AOP every time you want to know what happens in this method, you should check your xml config and find corresponding method, which is way less elegant.
On other hand, it's very hard to debug or use these proxies for any other declarative management. E.g. it's tricky (but not impossible) extract your bean from context and get something out of your wrapped bean using reflection (let's say, for monitoring purposes). In addition, when bean calls one of its method, it won't be delegated to proxy, because your bean knows nothing about proxy, so this refers to bean itself. The only way to cure this it to provide "self" field and set it in custom bean postprocessor (but your implementation suffers from this either).
Implementation
If Spring is configured to use transactional management, it's looking for #Transactional annotation on bean's definitions and creates auto-generated AOP proxy, which is subclass of your bean. Default behavior of Spring proxy is just delegating method's calls to underlying bean. Then Spring injects TransactionInterceptor with necessary TransactionManagers.
Code of interceptor looks quite simple:
public Object invoke(final MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {#code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
#Override
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
}
Inside of invokeWithinTransaction TransactionInterceptor determines whether should invocation be in scope of caller transaction (if one exists) or in a new one (it's about propagation level). Then it choses corresponding TransactionManager, configures timeout and isolation level, then invokes the method. After it decides if transaction should be commited or rolled back (choice is made based on caught exception and timing).

Clarification Request about Declarative Transaction via XML configuration in Spring Framework

I am studying Spring Declarative Transaction via XML configuration reading this article:
http://www.tutorialspoint.com/spring/declarative_management.htm
I am only having some proble to understand well how AOP work in this case, in my Beans.xml configuration file I have:
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="create"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="createOperation"
expression="execution(* com.tutorialspoint.StudentJDBCTemplate.create(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="createOperation"/>
</aop:config>
So, what exactly means this configuration?
I think that work in the following way (but I am not sure):
The transaction semantics to apply are encapsulated in the definition and I think that, in this case, simply specify that the create() method definied in the StudentDAO interface have to be a transactional behavior (is it right?)
Regarding the meaning of the content of aop:config tag I think that only ensure that the above transactional advice runs for any execution of com.tutorialspoint.StudentJDBCTemplate.create() method
Is it right? Or am I missing something?
Tnx
Andrea
You are right,
aop:pointcut will find out all the joinpoints where advise should be applied, defined with tx:advice.
also tx:advice gives extra tags to filter out these join points using tx:method tags with method attribute.
In above mentioned example,
pointcut will find only one joinpoint, and tx:advice will filter out joinpoints with tx:method's name attribute and apply specified configuration.In example default configuration values will be used.

hibernate/spring is trying to insert rather than save (record already exists in db) after the previous transaction failed

I have a batch interface class that creates a hibernate Session like this:
Session session = SessionFactoryUtils.getSession(sessionFactory, true);
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
Then it calls a service to get a list of objects from the DB, and in the batch class it iterates through that list and for each object it makes a service call to do some processing against the object.
Say on the 2nd object some nullpointerexception occurs somewhere, and i catch the exception in my batch class. Then i try to process the 3rd object and in the service when it tries to save the object, by calling HibernateDaoSupport.getSession(false).save(object) - it actually tries to insert it (and i get an error because a record already exists) instead of updating it.
This only happens if the previous object failed. If an exception occurs does it do something w/ that Hibernate session? Any ideas whats going on?
I have the following in my app context.xml
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="*" rollback-for="Throwable"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="serviceMethods" expression="execution(* com.company.service..*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethods" />
</aop:config>
Session.save is supposed to assign an identifier to a transient instance and persisting it by doing an insert. I'm rather surprised that it doesn't do this in your first service call.
And since a NPE occurs in your service call, the transaction is rolled back (since you configured it with <tx:method name="*" rollback-for="Throwable"/>), which could explain some differences between the succeeding calls and the failing ones. I don't know what your two first lines of code are supposed to do, but as Bozho said, you should not bind resources to the TransactionSynchronizationManager yourself. It's Spring's responsibility.
Let spring create your session and manage your transactions. The TransactionSynchornizationManager is something that you should not normally use.

Categories

Resources