【发布时间】:2012-03-24 20:56:32
【问题描述】:
这是与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 处理异常时重定向总是需要很长时间),但问题是事务实际上并没有回滚。我不知道为什么。如果我检查事务的状态,它会说它没有处于回滚状态。
您将如何最好地处理取消请求。在这种情况下,纯手动冲洗不起作用。您可以使用分离的实体,但页面包含多个链接实体,所以这会变得混乱。
更新:我现在发现抛出 ApplicationException 并不会在所有情况下回滚事务。现在很困惑。
更新 2:当然,当您有一个使用 ajax 更新值的页面时,回滚事务将不起作用。每个事务只涵盖一个请求。所以,如果你这样做,例如使用 ajax 请求进行 5 次编辑,回滚事务只会回滚上次 ajax 请求的更改,而不是前 4 次的更改。
所以真正的解决方法是使用冲洗模式MANUAL。
即使您指定了 MANUAL,也有一些事情会导致刷新。
- ajax 请求中的查询可能会触发刷新 - 对查询使用 setFlushMode(FlushMode.COMMIT) 来避免这种情况。
- 根据所使用的 ID 生成(例如,如果您使用策略 IDENTITY),持久化实体可能会触发刷新。您可以使用 Cascades 解决此问题。如果您需要在编辑期间创建与您正在编辑的主要实体没有任何实际关系的实体,只需将它们添加到列表中,并在您保存时将所有实体保留在该列表中。
- 当您开始嵌套对话或另一个 bean 加入对话时,如果您未指定 @Begin(join=true,flushMode=FlushModeType.MANUAL),该会话上的刷新模式将设置回 AUTO
您可能希望在 components.xml 中将 MANUAL 指定为默认模式
<core:manager concurrent-request-timeout="10000"
conversation-id-parameter="cid" conversation-timeout="600000" default-flush-mode="MANUAL"/>
【问题讨论】:
-
你试过Transaction.instance().setRollbackOnly()吗?
标签: java hibernate transactions seam rollback