Chapter 3. JMS Transactions
Abstract
JMS endpoints create special problems when transactions are enabled. Their behavior is effected by the type of transaction manager in use, the caching level in use, and the message exchange pattern in use.
Note
For tips on optimizing transaction performance, see Appendix A, Optimizing Performance of JMS Single- and Multiple-Resource Transactions.
3.1. Configuring the JMS Component
Overview
To enable transactions in a JMS component (thus enabling JMS endpoints to play the role either of a transactional resource or a transactional client), you need to:
- set the transacted property
- provide the JMS component with a reference to a suitable transaction manager
In addition, you may want to adjust the JMS component's cache level setting. External transaction managers can impact caching performance.
Camel JMS component configuration
The easiest way to configure a JMS endpoint to participate in transactions is to create a new an instance of a Camel JMS component that has the proper settings. To do so:
- Create a
bean
element that has itsclass
attribute set toorg.apache.camel.component.jms.JmsComponent
.This bean creates an instance of the JMS component. - Set the bean's
id
attribute to a unique, short, string.The id will be used to create route endpoint's that use this JMS component. - Add an empty
property
child to the bean. - Add a
name
attribute with the value ofconfiguration
to theproperty
element. - Add a
ref
attribute whose value is the id of aJmsConfiguration
bean to theproperty
element.TheJmsConfiguration
bean is used to configure the JMS component. - Create a
bean
element that has itsclass
attribute set toorg.apache.camel.component.jms.JmsConfiguration
.This bean creates an instance of the JMS component configuration. - Add a
property
child to the bean to configure the JMS connection factory.- Set the
name
attribute toconnectionFactory
. - Set the
ref
attribute to the id of a bean that configures a JMS connection factory.
- Add an empty
property
child to the bean that specifies the transaction manager the component will use.- Set the
name
attribute totransactionManager
. - Set the
ref
attribute to the id of a bean that configures transaction manager the endpoint will use.
- Add an empty
property
child to the bean that configures the component to participate in transactions.- Set the
name
attribute totransacted
. - Set the
value
attribute totrue
.The transacted property determines if the endpoint can participate in transactions.
- Optionally add an empty
property
child to the bean to change the default cache level.- Set the
name
attribute tocacheLevelName
. - Set the
value
attribute to to a valid cache level. For details, see the section called “Cache levels and performance”.
The
JmsComponent
bean's id
specifies the URI prefix used by JMS endpoints that will use the transactional JMS component. For example, in Example 3.1, “JMS Transaction Manager Configuration” the JmsComponent
bean's id
equals jmstx
, so endpoint that use the configured JMS component use the jmstx:
prefix.
The
JmsConfiguration
class supports a large number of other properties, which are essentially identical to the JMS URI options described in chapter "JMS" in "Apache Camel Component Reference".
Cache levels and performance
The settings for JMS cache level can impact performance when you are using transactions. The default cache level is
CACHE_AUTO
. This default auto detects if an external transaction manager is in use and sets the cache level as follows:
CACHE_CONSUMER
if only local JMS resources are in useCACHE_NONE
if an external transaction manager is in use
If your transaction manager does not require that caching be disabled, you can raise the cache level to improve performance. Consult your transaction manager's documentation to determine what caching level it can support. Then override the default cache level by setting the JMS component's cacheLevelName property to the new cache level.
See chapter "JMS" in "Apache Camel Component Reference" for information on setting the cache level of the JMS component.
Caching with ActiveMQ endpoints
When the transactional resource is ActiveMQ, you can use either
CACHE_CONNECTION
or CACHE_CONSUMER
for local JMS transactions.
CACHE_CONSUMER
improves performance significantly, but to avoid losing messages on failover:
- Do not set a transaction manager, and
- Set the lazyCreateTransactionManager property to
false
in your JMS configuration.
For an example route definition using
CACHE_CONNECTION
, see the section called “Example using CACHE_CONNECTION”. For an example route definition using CACHE_CONSUMER
, see the section called “Example using CACHE_CONSUMER”.
Important
Be careful when configuring caching with local transactions. The configurations shown in the section called “Example using CACHE_CONNECTION” and the section called “Example using CACHE_CONSUMER” are believed to be safe (that is, no risk of message loss) for configuring Camel routes where the consumer and producer endpoints both connect to the same broker instance. For other configurations involving local transactions, it is generally safer to disable caching (
CACHE_NONE
).
Example using CACHE_CONSUMER
This route definition routes messages between two destinations on the same broker using local transactions. Not setting a transaction manager makes Spring use only one JMS session and one transaction. The Camel route is fully transacted because the Camel consumer and producer endpoints are transacted.
<camel:camelContext trace="false" id="My.impl.CamelContext">
<camel:route id="Queue2Backend">
<camel:from uri="activemq:queue:TEST.amq.failover.inputQueue" />
<camel:log message="Sending message to backend..."/>
<camel:to uri="activemq:queue:TEST.amq.failover.backendQueue" />
</camel:route>
</camel:camelContext>
<bean id="jmsConectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop">
<property name="connectionFactory">
<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="failover:(tcp://localhost:61616?wireFormat.
tightEncodingEnabled=false)?initialReconnectDelay=10000&useExponentialBackOff=false
&maxReconnectDelay=10000"/>
<property name="userName" value="admin"/>
<property name="password" value="admin"/>
</bean>
</property>
<property name="maxConnections" value="1"/>
</bean>
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="jmsConectionFactory"/>
<property name="lazyCreateTransactionManager" value="false"/>
<property name="transacted" value="true"/>
<property name="concurrentConsumers" value="1"/>
<property name="cacheLevelName" value="CACHE_CONSUMER"/>
</bean>
<bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="configuration" ref="jmsConfig"/>
</bean>
Example using CACHE_CONNECTION
Example 3.1, “JMS Transaction Manager Configuration” shows the configuration of a JMS component,
jmstx
that supports Spring transactions. The JMS component is layered over an embedded instance of Apache ActiveMQ and the transaction manager is an instance of JmsTransactionManager
.
Example 3.1. JMS Transaction Manager Configuration
<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="jmstx" class="org.apache.camel.component.jms.JmsComponent"> <property name="configuration" ref="jmsConfig" /> </bean> <bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration"> <property name="connectionFactory" ref="jmsConnectionFactory"/> <property name="transactionManager" ref="jmsTransactionManager"/> <property name="transacted" value="true"/> <property name="cacheLevelName" value="CACHE_CONNECTION"/> </bean> <bean id="jmsTransactionManager" class="org.springframework.jms.connection.JmsTransactionManager"> <property name="connectionFactory" ref="jmsConnectionFactory" /> </bean> <bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"> <property name="brokerURL" value="vm://broker1?brokerConfig=xbean:tutorial/activemq.xml"/> </bean> </beans>
To use this JMS component in a route you would use the URI prefix jmstx: as shown in Example 3.2, “URI for Using Transacted JMS Endpoint”.
Example 3.2. URI for Using Transacted JMS Endpoint
from("jmstx:queue:rawStockQuotes") .process(myFormatter) .to("jmstx:queue:formattedStockQuotes");