手动回滚Seam中的事务

时间:2012-03-07 10:23:32

标签: java hibernate transactions seam rollback

这与Forcing a transaction to rollback on validation error类似的问题 场景是这样的: 用户编辑页面,事务设置为MANUAL,因此只有当我们调用flush时才会将其提交到数据库。现在用户想要取消更改。很容易,因为你还没有冲洗它。

现在考虑这种情况:用户编辑页面上有很多ajax。其中一些ajax回调需要数据库查询(例如,使用richFaces建议框等)。还进行了一些验证,需要进行数据库查找。问题是Hibernate会在您执行查询时自动发出刷新。因此用户不按下取消按钮时的保存按钮(这将刷新交易)。你现在做什么?

如果您不做任何操作,更改将写入数据库 - 而不是用户期望的内容。

您可以抛出使用

注释的异常
@ApplicationException(rollback=true)

这会回滚交易。然后,您可以重定向到另一个页面。但是在这里我遇到了另一个问题,在某些页面上你重定向到你会得到一个懒惰的初始化异常。我指定了

<exception class="com.mycomp.BookingCancelException">
    <end-conversation before-redirect="true"/>  
    <redirect view-id="/secure/Bookings.xhtml">
        <message severity="INFO">#{messages['cancel.rollback']}</message>
    </redirect>
</exception>
在pages.xml中

,所以在我们进行重定向之前,对话应该结束。应该开始新的对话(使用新的交易),但似乎并非在所有情况下都会发生?为什么呢?

我在其他地方读过你可以简单地使用

Transaction.instance().rollback();

这是首选,因为您不必通过异常(当Seam处理异常时重定向总是需要很长时间),但问题是事务实际上没有回滚。我无法弄清楚为什么。如果我检查事务的状态,它表示它不处于回滚状态。

您如何最好地处理取消请求。在这种情况下,纯MANUAL刷新不起作用。您可以使用分离的实体,但页面包含多个链接的实体,因此这变得很混乱。

更新:我现在发现抛出ApplicationException并不会在所有情况下回滚事务。所以现在很困惑。

更新2 :当您拥有使用ajax更新值的页面时,回滚事务当然不起作用。每笔交易仅涵盖一个请求。所以如果你这样做,使用ajax请求进行5次编辑,回滚事务只会回滚上一次ajax请求的更改,而不是之前的4次更改。

因此解决方案实际上是使用冲洗模式MANUAL。

即使您指定MANUAL,也有一些事情会导致刷新。

  • ajax请求中的查询可以触发刷新 - 对查询使用setFlushMode(FlushMode.COMMIT)以避免这种情况。
  • 持久化实体可以根据所使用的ID生成触发刷新(例如,如果您使用策略IDENTITY)。您可以使用Cascades解决这个问题。如果您需要在编辑期间创建与您正在编辑的主实体没有任何实际关系的实体,只需将它们添加到列表中,并在执行保存时保留该列表中的所有实体。
  • 当您启动嵌套对话或其他bean加入对话时,当您未指定@Begin(join = true,flushMode = FlushModeType.MANUAL)时,该会话上的Flush Mode将重新设置为AUTO

您可能希望将MANUAL指定为components.xml

中的默认模式
<core:manager concurrent-request-timeout="10000"
  conversation-id-parameter="cid" conversation-timeout="600000" default-flush-mode="MANUAL"/>

3 个答案:

答案 0 :(得分:0)

你试过吗

@Begin(flushMode=MANUAL)
someRandomValidationMethodHere(){ ... }

或设置

<core:manager conversation-timeout="120000" default-flush-mode="manual" />

在components.xml中?

答案 1 :(得分:0)

知道您可以使用属性bypassUpdates告诉ajax验证组件不要刷新可能会有所帮助。这是一篇文章explaining

答案 2 :(得分:0)

您可以管理交易并使用激活的按钮进行管理。

    protected void doGet(HttpServletRequest request,
                         HttpServletResponse response, String butonPressed)
            throws ServletException, IOException {

        try {
            // Begin unit of work
            HibernateUtil.getSessionFactory()
                    .getCurrentSession().beginTransaction();

        } catch (Exception ex) {
            HibernateUtil.getSessionFactory()
                    .getCurrentSession().getTransaction().rollback();
            throw new ServletException(ex);
        }
        finally
        {
            if ("SAVE".equals(butonPressed))
            {

            // Process request and render page...

            // End unit of work
            HibernateUtil.getSessionFactory()
                    .getCurrentSession().getTransaction().commit();
            }
            else
            {
                HibernateUtil.getSessionFactory()
                        .getCurrentSession().getTransaction().rollback();
            }
        }

    }