5.3. Propagation Policies
Overview
If you want to influence the way a transactional client creates new transactions, you can do so by specifying a transaction policy for it. In particular, Spring transaction policies enable you to specify a propagation behavior for your transaction. For example, if a transactional client is about to create a new transaction and it detects that a transaction is already associated with the current thread, should it go ahead and create a new transaction, suspending the old one? Or should it simply let the existing transaction take over? These kinds of behavior are regulated by specifying the propagation behavior on a transaction policy.
Transaction policies are instantiated as beans in Spring XML. You can then reference a transaction policy by providing its bean ID as an argument to the
transacted()
DSL command. For example, if you want to initiate transactions subject to the behavior, PROPAGATION_REQUIRES_NEW
, you could use the following route:
from("file:src/data?noop=true") .transacted("PROPAGATION_REQUIRES_NEW") .beanRef("accountService","credit") .beanRef("accountService","debit") .to("file:target/messages");
Where the
PROPAGATION_REQUIRES_NEW
argument specifies the bean ID of a transaction policy bean that is configured with the PROPAGATION_REQUIRES_NEW
behavior (see Example 5.1, “Transaction Policy Beans”).
Spring transaction policies
Apache Camel lets you define Spring transaction policies using the
org.apache.camel.spring.spi.SpringTransactionPolicy
class (which is essentially a wrapper around a native Spring class). The SpringTransactionPolicy
class encapsulates two pieces of data:
- A reference to a transaction manager (of
PlatformTransactionManager
type). - A propagation behavior.
For example, you could instantiate a Spring transaction policy bean with
PROPAGATION_MANDATORY
behavior, as follows:
<beans ...> <bean id="PROPAGATION_MANDATORY "class="org.apache.camel.spring.spi.SpringTransactionPolicy"> <property name="transactionManager" ref="txManager"/> <property name="propagationBehaviorName" value="PROPAGATION_MANDATORY"/> </bean> ... </beans>
Propagation behaviors
The following propagation behaviors are supported by Spring (where these values were originally modelled on the propagation behaviors supported by J2EE):
PROPAGATION_MANDATORY
- Support a current transaction; throw an exception if no current transaction exists.
PROPAGATION_NESTED
- Execute within a nested transaction if a current transaction exists, else behave like
PROPAGATION_REQUIRED
.NoteNested transactions are not supported by all transaction managers. PROPAGATION_NEVER
- Do not support a current transaction; throw an exception if a current transaction exists.
PROPAGATION_NOT_SUPPORTED
- Do not support a current transaction; rather always execute non-transactionally.NoteThis policy requires the current transaction to be suspended, a feature which is not supported by all transaction managers.
PROPAGATION_REQUIRED
- (Default) Support a current transaction; create a new one if none exists.
PROPAGATION_REQUIRES_NEW
- Create a new transaction, suspending the current transaction if one exists.NoteSuspending transactions is not supported by all transaction managers.
PROPAGATION_SUPPORTS
- Support a current transaction; execute non-transactionally if none exists.
Defining policy beans in Spring XML
Example 5.1, “Transaction Policy Beans” shows how to define transaction policy beans for all of the supported propagation behaviors. For convenience, each of the bean IDs matches the specified value of the propagation behavior value, but in practice you can use whatever value you like for the bean IDs.
Example 5.1. Transaction Policy Beans
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd"> ... <bean id="PROPAGATION_MANDATORY "class="org.apache.camel.spring.spi.SpringTransactionPolicy"> <property name="transactionManager" ref="txManager"/> <property name="propagationBehaviorName" value="PROPAGATION_MANDATORY"/> </bean> <bean id="PROPAGATION_NESTED" class="org.apache.camel.spring.spi.SpringTransactionPolicy"> <property name="transactionManager" ref="txManager"/> <property name="propagationBehaviorName" value="PROPAGATION_NESTED"/> </bean> <bean id="PROPAGATION_NEVER" class="org.apache.camel.spring.spi.SpringTransactionPolicy"> <property name="transactionManager" ref="txManager"/> <property name="propagationBehaviorName" value="PROPAGATION_NEVER"/> </bean> <bean id="PROPAGATION_NOT_SUPPORTED" class="org.apache.camel.spring.spi.SpringTransactionPolicy"> <property name="transactionManager" ref="txManager"/> <property name="propagationBehaviorName" value="PROPAGATION_NOT_SUPPORTED"/> </bean> <!-- This is the default behavior. --> <bean id="PROPAGATION_REQUIRED" class="org.apache.camel.spring.spi.SpringTransactionPolicy"> <property name="transactionManager" ref="txManager"/> </bean> <bean id="PROPAGATION_REQUIRES_NEW" class="org.apache.camel.spring.spi.SpringTransactionPolicy"> <property name="transactionManager" ref="txManager"/> <property name="propagationBehaviorName" value="PROPAGATION_REQUIRES_NEW"/> </bean> <bean id="PROPAGATION_SUPPORTS" class="org.apache.camel.spring.spi.SpringTransactionPolicy"> <property name="transactionManager" ref="txManager"/> <property name="propagationBehaviorName" value="PROPAGATION_SUPPORTS"/> </bean> </beans>
Note
If you want to paste any of these bean definitions into your own Spring XML configuration, remember to customize the references to the transaction manager. That is, replace references to
txManager
with the actual ID of your transaction manager bean.
Sample route with PROPAGATION_NEVER policy in Java DSL
A simple way of demonstrating that transaction policies have some effect on a transaction is to insert a
PROPAGATION_NEVER
policy into the middle of an existing transaction, as shown in the following route:
from("file:src/data?noop=true") .transacted() .beanRef("accountService","credit") .transacted("PROPAGATION_NEVER") .beanRef("accountService","debit");
Used in this way, the
PROPAGATION_NEVER
policy inevitably aborts every transaction, leading to a transaction rollback. You should easily be able to see the effect of this on your application.
Note
Remember that the string value passed to
transacted()
is a bean ID, not a propagation behavior name. In this example, the bean ID is chosen to be the same as a propagation behavior name, but this need not always be the case. For example, if your application uses more than one transaction manager, you might end up with more than one policy bean having a particular propagation behavior. In this case, you could not simply name the beans after the propagation behavior.
Sample route with PROPAGATION_NEVER policy in Spring XML
The preceding route can be also be defined in Spring XML, as follows:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ... > <camelContext xmlns="http://camel.apache.org/schema/spring"> <route> <from uri="file:src/data?noop=true"/> <transacted/> <bean ref="accountService" method="credit"/> <transacted ref="PROPAGATION_NEVER"/> <bean ref="accountService" method="debit"/> </route> </camelContext> </beans>