I am writing a simple application (Spring + Hibernate + PostgreSql db). I am just trying to construct a sample object and persist in db.
I run a simple java class main method where i have loaded the applicationContext and have got reference to the service class as below
TestService srv = (TestService)factory.getBean("testService");
Application Context - context :
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactoryVsm" />
</bean>
<bean id="testService" class="com.test.service.TestServiceImpl">
<property name="testDao" ref="testDao"/>
</bean>
<bean id="testDao" class="com.test.dao.TestDaoImpl>
<property name="sessionFactory" ref="sessionFactoryVsm"/>
</bean>
In TestService I have injected TestDao. In test service method I have constructed to employee objects emp1 and emp2 and calling dao twice to update.
TestDaoImpl code:
public void saveOrUpdate(BaseDomainModel baseObject) {
Session session = null;
try {
session = getHibernateTemplate().getSessionFactory().openSession();
session.saveOrUpdate(baseObject);
session.flush();
} catch (Exception e) {
logger.error("Generic DAO:saveOrUpdate::" + e);
e.printStackTrace();
} finally {
if (session != null) {
session.close();
}
}
}
When emp2 update fails emp1 should also fail. How do I do that. Please advice
Thanks in advance
Updated :
Thanks Nanda. I tried Declarative transaction. But it is not working. emp1 gets persisted and not rolled back eveb second dao call fails. I have added transaction advice to the method.
to test if the transaction advice is applied or not i changed the propagation to "NOT_SUPPORTED". but still emp1 gets persisted. the expectation is we should have got Transaction Not Supported type of exception. please advice .
UPDATED
@seanizer - Thanks for the update. I have even tried adding
@Transactional(propagation=Propagation.NOT_SUPPORTED)
public void saveEmp(Employee emp)
to that service method. But it didn't work. Moreover iterating the collection<BaseDomainModel>
hold good only if i need to call one dao. If in case i have to call two different dao to persist obj1 and obj2- this may not help. Just to check if the transaction is getting applied I get
@Transactional(propagation=Propagation.NOT_SUPPORTED)
.
But still obj1 got persisted.
I just doubt if the xml configuration/ annotation given is correct. please check
<bean id="txManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactoryVsm" />
</bean>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="saveEmp" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="testServiceOperation" expression="execution(*com.test.service.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="testServiceOperation"/>
</aop:config>
I am using org.springframework.orm.hibernate3.HibernateTransactionManager for the transactionManager. Is this correct ?
Updated
I have created my exception class myRuntimeExp extending from RuntimeException and throwing the same from Dao method to the service method. but still the rollback is not happening. I just doubt if I have correctly given the configurations in the applnContext.xml. Can someone help me how to check if the transaction advice / annotation is being applied to the method or not? is there any way of running it in a debugging mode and check
Issue :
I was using
session = getHibernateTemplate().getSessionFactory().openSession();
But it should be current session and it is working fine.
session = getHibernateTemplate().getSessionFactory().getCurrentSession();
If you use declarative transaction management, you can lose most of this boilerplate:
TestDaoImpl:
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory f){
this.sessionFactory = f;
}
public void saveOrUpdate(BaseDomainModel baseObject) {
Session session = sessionFactory.getCurrentSession();
session.saveOrUpdate(baseObject);
}
And you can control the transaction handling from the service layer using @Transactional
(or xml configuration)
TestServiceImpl:
private TestDao testDao;
public void setTestDao(TestDao d){
this.testDao = d;
}
@Transactional // one transaction for multiple operations
public void someServiceMethod(Collection<BaseDomainModel> data){
for(BaseDomainModel baseObject : data)
testDao.saveOrUpdate(baseObject);
}
Reference:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With