This is a similar problem for Forcing a transaction to rollback with a validation error. The scenario is as follows: The user edits the page, the transaction is set to MANUAL, so only if we call flush will it be bound to the database. Now the user wants to discard the changes. Easy until you have painted it.
Now consider this scenario: A user edits a page with a lot of ajax. Some of these ajax callbacks require database queries (for example, using the richFaces suggestions window, etc.). Some validation is also performed, which requires a database search. The problem is that Hibernate automatically issues a flash when the request is executed. Thus, the user does not press the save button (which will hide the transaction), he presses the cancel button. What are you doing now?
If you do nothing, the changes will be written to the database - not what the user expects.
You can create an exception that is annotated with
@ApplicationException(rollback=true)
This will roll back the transaction. Then you can redirect to another page. However, here I ran into another problem, on some pages that you redirect to you, a lazy initialization exception occurs. I pointed
<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>
in pages.xml, so the conversation should end before we redirect. A new conversation should begin (with a new transaction), but it seems that this does not happen in all cases? Why?
I read somewhere else that you can just use
Transaction.instance().rollback();
This would be preferable since you don't have to go through exceptions (redirecting always takes a lot of time when Seam handles the exceptions), but the problem is that the transaction does not actually roll back. I could not understand why. If I check the status of the transaction, it says that it is not in a rollback state.
How would you best handle Cancel requests. In this case, the clean MANUAL knob does not work. You can work with individual objects, but the page contains several related objects, so this becomes messy.
Update : I have now found that throwing ApplicationException does not cancel the transaction in all cases. So now it's pretty confusing.
Update 2 . Of course, transaction rollback will not work if you have a page where you use ajax to update values. Each transaction covers only one request. So if you do this, for example, 5 changes using an ajax request, the transaction rollback will only discard the changes from the last ajax request, and not from the earlier 4.
Thus, the solution really should use the MANUAL manual mode.
There are a few things that will cause a flash, even if you specify MANUAL.
- a request in an ajax request can trigger a flash - use setFlushMode (FlushMode.COMMIT) in the request to avoid this.
- Saving an entity may cause a flash depending on the identifier generation used (for example, if you use the IDENTITY strategy). You can get around this using Cascades. If you need to create objects during editing that have no real relationship with the main object that you are editing, just add them to the list and save all the entities in this list when you do the save.
- When you start a nested conversation or another bean, the conversation connects, the Flush mode in this session is set to AUTO, unless you specify @Begin (join = true, flushMode = FlushModeType.MANUAL)
You can specify MANUAL as the default mode in components.xml
<core:manager concurrent-request-timeout="10000" conversation-id-parameter="cid" conversation-timeout="600000" default-flush-mode="MANUAL"/>