如何在不丢失封装的情况下进行事务处理?

时间:2011-05-04 06:53:37

标签: java hibernate transactions

我有一个保存bean的代码,并通过Hibernate更新数据库中的另一个bean。它必须在同一个事务中执行,因为如果出现错误(f.ex启动异常),则必须对这两个操作执行回滚。

public class BeanDao extends ManagedSession {

public Integer save(Bean bean) {
    Session session = null;
    try {
        session = createNewSessionAndTransaction();

        Integer idValoracio = (Integer) session.save(bean);  // SAVE
        doOtherAction(bean);                                 // UPDATE

        commitTransaction(session);

        return idBean;
    } catch (RuntimeException re) {
        log.error("get failed", re);
        if (session != null) {
            rollbackTransaction(session);
        }
        throw re;
    }
}

private void doOtherAction(Bean bean) {
    Integer idOtherBean = bean.getIdOtherBean();
    OtherBeanDao otherBeanDao = new OtherBeanDao();
    OtherBean otherBean = otherBeanDao.findById(idOtherBean);
    .
    . (doing operations)
    .
    otherBeanDao.attachDirty(otherBean)
}
}

问题是:

如果是

session.save(bean)

启动错误,然后我得到AssertionFailure,因为函数doOtherAction(在项目的其他部分中使用)在抛出异常后使用会话。

我想到的第一件事是提取函数doOtherAction的代码,但后来我有相同的代码重复,似乎不是最好的做法。

重构这个的最佳方法是什么?

3 个答案:

答案 0 :(得分:0)

在DAO,服务或其他业务逻辑类之上管理一个级别的事务是一种常见做法。这样,基于业务/服务逻辑,您可以在一个案例中在一个事务中执行两个DAO操作,在另一个案例中,在单独的事务中执行它们。

答案 1 :(得分:0)

我是声明式交易管理的忠实粉丝。如果你可以腾出时间让它工作(带有Application Server的小蛋糕,如GlassFish或JBoss,轻松使用Spring)。如果您使用@TransactionAttribute(REQUIRED)注释您的业务方法(它甚至可以设置为默认设置)并且它调用两个DAO方法,您将得到您想要的:一切都立即提交或回滚到异常。 这个解决方案与它得到的松散耦合一样。

答案 2 :(得分:0)

其他人是正确的,因为他们考虑到目前的常见做法。

但这并不能真正帮助您完成目前的练习。

您应该做的是创建两个新的DAO方法。例如CreateGlobalSession和CommitGlobalSession。

这些与您当前的创建和提交例程的作用相同。

不同之处在于它们设置了一个“全局”会话变量(最有可能最好用ThreadLocal完成)。然后,您更改当前例程,以便检查此全局会话是否已存在。如果您的create检测到全局会话,则只需返回它。如果您的提交检测到全局会话,那么它什么都不做。

现在,当您想要使用它时,您可以这样做:

try {
    dao.createGlobalSession();
    beanA.save();
    beanb.save();
    Dao.commitGlobalSession();
} finally {
    dao.rollbackGlobalSession();
}

确保将进程包装在try块中,以便在出现错误时重置全局会话。

虽然其他技术被认为是最佳实践,但理想情况下,有一天你可能会发展成类似的东西,这将使你获得超过3种新方法并改变现有方法的优势。之后,其余代码保持不变。