【问题标题】:Two dao methods in a single Spring @Transaction单个 Spring @Transaction 中的两个 dao 方法
【发布时间】:2013-09-19 04:28:48
【问题描述】:

我在 Hibernate 中使用 Spring 的 @Transactional。 我正在尝试将两个 dao 方法放入单个事务中,并希望回滚特定的异常。 代码如下:

服务类方法:

@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;
}

道法:

@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配置:

<tx:annotation-driven transaction-manager="txManager"/>
   <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
   </bean>

如果这两种方法(updateSelfAccount,updateAnotherAccount)中的任何一种失败,整个事务应该回滚。 但是即使我不确定这一切都发生在单个事务中,它也无法回滚给定的异常。 请纠正我。

【问题讨论】:

    标签: java spring hibernate transactions


    【解决方案1】:

    使用@Transactional 注解的目的是你的代码不应该处理事务本身。在您的代码示例中,您使用 @Transactional 所以您不必做类似

    的事情
    session.beginTransaction();
    

    您是否正确设置了弹簧

    <bean id="txManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="datasource" ref="dataSource"
    </bean>
    
    <tx:annotation-driven transaction-manager="transactionManager"/>
    

    通常 sessionFactory 在 dao 中是 @Autowired,以便轻松访问您所做的会话

    sessionFactory.getCurrentSession()

    最后一点,您不需要进行大的尝试捕获然后抛出 TransactionUnSuccessException ,默认情况下,事务将在任何异常时回滚。

    【讨论】:

    • 我已经编辑了我的代码,请看一下。你的意思是我们不应该在@Transactional的情况下自己处理事务。
    • 是的,如果您使用@Transactional,您的代码不应处理事务
    • 当我注释掉 session.beginTransaction() 它说 org.hibernate.HibernateException: createQuery is not valid without active transaction.
    【解决方案2】:

    对于初学者来说,不要使用HibernateTemplate 和/或HibernateDaoSupport,它们应该被视为已弃用。直接使用SessionFactory。接下来永远不要在 Spring 管理的事务中使用openSession,因为这将打开一个新会话,而不是绑定到事务和 spring 之外。在SessionFactory 上使用getCurrentSession

    最后从不捕获并吞下异常,来自 spring 的 TransactionInterceptor 需要异常来决定做什么(回滚或提交)

    重构您的 DAO 以包含所有这些。

    @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;
        }
    

    从更新量来看,另一个观察结果是您有映射问题。当您的映射正确时,您应该只需要更新/保存您的 User 对象,然后其他所有内容都应该自动持久化。

    还有一个观察,你不应该绕过会话,只需调用 getSession() 方法(我添加到 dao 中)。在整个交易过程中,您应该得到相同的Session

    最后观察,您的 dao 似乎包含业务逻辑,而应该在 service 方法中(例如检查帐户余额)。

    【讨论】:

      猜你喜欢
      • 2011-04-22
      • 1970-01-01
      • 2023-02-21
      • 2013-07-25
      • 2011-02-21
      • 2016-01-24
      • 2017-06-18
      • 2013-07-22
      • 2013-06-05
      相关资源
      最近更新 更多