So far we have seen transaction success or failure determined naturally—that is, by whether an exchange was successfully processed, or if an exception was thrown during its processing. This recipe will provide you with a number of additional options around controlling transaction rollback.
The Java code for this recipe is located in the org.camelcookbook.transactions.rollback
package. The Spring XML files are located under src/main/resources/META-INF/spring
and prefixed with rollback
.
You can use the rollback
DSL statement to throw an exception with an optional message.
In the XML DSL, we use the following code:
<from uri="direct:transacted"/>
<transacted/>
<setHeader headerName="message">
<simple>${body}</simple>
</setHeader>
<to uri="sql:insert into audit_log (message) values (:#message)"/>
<choice>
<when>
<simple>${body} contains 'explode'</simple>
<rollback message="Message contained word 'explode'"/>
</when>
</choice>
In the Java DSL, the same thing is expressed as follows:
from("direct:transacted")
.transacted()
.setHeader("message", body())
.to("sql:insert into audit_log (message) values (:#message)")
.choice()
.when(simple("${body} contains 'explode'"))
.rollback("Message contained word 'explode'")
.endChoice();
When an exchange triggers a rollback, a org.apache.camel.RollbackExchangeException
object is thrown with the message specified. This will cause the transaction error handler to rollback any transactions currently in progress for this exchange. The exception itself will be wrapped in an org.apache.camel.CamelExecutionException
instance before being returned to the consuming endpoint.
Being a regular exception, a rollback may be caught by an onException
block, such as:
.onException(RollbackExchangeException.class) .log("Caught rollback signal") .end()
You can trigger rollback behavior without an exception being thrown through the use of the markRollbackOnly
statement. This will cause the exchange to stop being processed immediately, and any transactions currently in progress to be rolled back. Camel will consider the exchange's processing to have been successfully completed.
In the XML DSL, markRollbackOnly
is an attribute of the rollback
element:
<choice>
<when>
<simple>${body} contains 'explode'</simple>
<rollback markRollbackOnly="true"/>
</when>
</choice>
In the Java DSL, it is a DSL statement in its own right:
.choice()
.when(simple("${body} contains 'explode'"))
.markRollbackOnly()
.endChoice()
If you are nesting transactions, it is possible to roll back the current, or deepest, transaction only by using markRollbackOnlyLast
. In the following example, a message that contains the word "explode" will cause the inner transaction, tx2
, to be rolled back. No further processing will take place in route2
, and so the exchange will not reach the mock:out2
endpoint. The exchange will, however, continue to be processed by route1
, and will therefore be sent to the mock:out1
endpoint. The transaction tx1
will be committed successfully:
<route id="route1"> <from uri="direct:route1"/> <setHeader headerName="message"> <simple>${body}</simple> </setHeader> <policy ref="PROPAGATION_REQUIRES_NEW" id="tx1"> <to uri="sql:insert into messages (message) values(:#message)"/> <to uri="direct:route2"/> <to uri="mock:out1"/> </policy> </route> <route id="route2"> <from uri="direct:route2"/> <policy ref="PROPAGATION_REQUIRES_NEW-2" id="tx2"> <to uri="sql:insert into audit_log (message) values(:#message)"/> <choice> <when> <simple>${body} contains 'explode'</simple> <rollback markRollbackOnlyLast="true"/> </when> </choice> <to uri="mock:out2"/> </policy> </route>
In the Java DSL, the equivalent logic is expressed as:
from("direct:route1").id("route1") .setHeader("message", simple("${body}")) .policy("PROPAGATION_REQUIRES_NEW").id("tx1") .to("sql:insert into messages (message) values (:#message)") .to("direct:route2") .to("mock:out1") .end(); from("direct:route2").id("route2") .policy("PROPAGATION_REQUIRES_NEW-2").id("tx2") .to("sql:insert into audit_log (message) values (:#message)") .choice() .when(simple("${body} contains 'explode'")) .markRollbackOnlyLast() .endChoice() .to("mock:out2") .end();
3.143.255.36