简体   繁体   中英

Two dao methods in a single Spring @Transaction

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.

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.

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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM