Reputation: 465
I am using Spring's @Transactional with Hibernate. I am trying to put two dao methods into a single transaction and want to rollback on a specific Exception. Code is as follows:
Service Class method:
@Transactional(propagation=Propagation.REQUIRES_NEW,value="txManager",rollbackFor=TransactionUnSuccessException.class)
public Account makeTransaction(Transaction transaction, String userName)
throws TransactionUnSuccessException {
Account account = null;
account = transferDao.makeTransaction(transaction, userName);
return account;
}
Dao methods:
@Repository
public class TransferDao extends HibernateDaoSupport {
@Autowired
private SessionFactory sessionFactory;
public Account makeTransaction(Transaction transaction, String userName)
throws TransactionUnSuccessException {
HibernateTemplate hibernateTemplate = getHibernateTemplate();
Account account = null;
Session session = hibernateTemplate.getSessionFactory().openSession();
//session.beginTransaction();
updateSelfAccount(transaction, userName, session);
account = updateAnotherAcccount(transaction, session);
//session.getTransaction().commit();
return account;
}
private void updateSelfAccount(Transaction transaction, String userName,
Session session) {
User currentUser = null;
System.out.println("TransferDao.updateSelfAccount()" + transaction);
Query query = session.createQuery("from User where userName=:userName");
query.setParameter("userName", userName);
currentUser = (User) query.list().get(0);
currentUser.getAccount().getTransactions().add(transaction);
currentUser.getAccount().setAvailableBalance(
currentUser.getAccount().getAvailableBalance()
- transaction.getAmount());
transaction.setTransAccount(currentUser.getAccount());
session.save(transaction);
session.update(currentUser.getAccount());
session.update(currentUser);
private Account updateAnotherAcccount(Transaction transaction,
Session session) throws TransactionUnSuccessException {
Account account = null;
try {
Query query = session
.createQuery("from Account where accNo=:accNo");
query.setParameter("accNo", transaction.getToAcc());
account = (Account) query.list().get(0);
if (account.getAvailableBalance() < 5000) {
account.setAvailableBalance(account.getAvailableBalance()
+ transaction.getAmount());
account.getTransactions().add(transaction);
transaction.setTransAccount(account);
session.save(transaction);
session.update(account);
} else {
throw new TransactionUnSuccessException();
}
} catch (TransactionUnSuccessException te) {
te.printStackTrace();
}
return account;
}
}
}
Xml configuration:
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
If any of the two method(updateSelfAccount,updateAnotherAcccount) fails the whole transaction is supposed to rollback. But It is not able to rollback on the given Exception even i am not sure that this is all happening in a single transaction. please correct me.
Upvotes: 0
Views: 3003
Reputation: 124441
For starters don't use HibernateTemplate
and/or HibernateDaoSupport
they should be considered deprecated. Use the SessionFactory
directly. Next NEVER use openSession
inside a Spring managed transaction as that will open en new session, not bound to the transaction and outside of spring. Use getCurrentSession
on the SessionFactory
instead.
Finally NEVER catch and swallow exceptions, the TransactionInterceptor from spring needs the exception to decide what to do (rollback or commit)
Refactor your DAO to include all this.
@Repository
public class TransferDao {
@Autowired
private SessionFactory sessionFactory;
private Session getSession() {
sessionFactory.getCurrentSession();
}
public Account makeTransaction(Transaction transaction, String userName) throws TransactionUnSuccessException {
Account account = null;
Session session = getSession();
updateSelfAccount(transaction, userName, session);
account = updateAnotherAcccount(transaction, session);
return account;
}
Another observation, judging from the amount of updates, is that you have a mapping problem. When your mappings are correct you should only have to bother with an update/save of your User
object, everything else should be automatically persisted then.
Yet another observation, you shouldn't pass around the session, simply call the getSession()
method (which I added to the dao). You should get the same Session
during the whole transaction.
Final observation, your dao seems to contain business logic, which should be in the service method instead (checking the account balance for instance).
Upvotes: 0
Reputation: 9639
The goal of using @Transactional annotation is that your code should not deal with the transaction itself. In your code example your use @Transactional so you should not have to do things like
session.beginTransaction();
Something else did you setup spring correctly with
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="datasource" ref="dataSource"
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
Usually the sessionFactory is @Autowired in the dao and to get an easy access to the session you do
sessionFactory.getCurrentSession()
Last point you don't need to have a big try catch and then throwing your TransactionUnSuccessException , by default the transaction will rollback on any exception.
Upvotes: 3