Apache Camel框架之事务控制

本文简单介绍一下Apache Camel如何对route进行事务控制,首先介绍整个route只涉及到一个事务参与者的情况,然后再介绍route中涉及到多个事务参与者的情况.Camel是通过和Spring的框架集成进行事务控制的.

1,整个route只有一个事务参与者,"局部事务",这里用JMS的例子,后台的MQ为ActiveMQ,示例图如下:(图片来源于Camel in Action)


route的代码如下:
源码打印?

    public class JMSTransaction extends RouteBuilder { 
        public void configure() throws Exception { 
            TProcessor0 p0 = new TProcessor0(); 
            TProcessor1 p1 = new TProcessor1(); 
            from("jms:queue:TOOL.DEFAULT").process(p0).process(p1).to("file:d:/temp/outbox");         
        } 
    } 

Spring配置如下:
源码打印?

    <beans xmlns="http://www.springframework.org/schema/beans" 
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
           xmlns:broker="http://activemq.apache.org/schema/core" 
           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 
           http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core-5.2.0.xsd"> 
        <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring"> 
            <package> 
                com.test.camel.transaction.jms 
            </package> 
        </camelContext>     
        <bean id="jms" class="org.apache.activemq.camel.component.ActiveMQComponent"> 
            <property name="transacted" value="true"/> 
            <property name="transactionManager" ref="txManager"/>             
        </bean> 
        <bean id="txManager" class="org.springframework.jms.connection.JmsTransactionManager"> 
            <property name="connectionFactory" ref="jmsConnectionFactory"/> 
        </bean> 
        <bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"> 
            <property name="brokerURL" value="tcp://localhost:61616"/>         
        </bean> 
    </beans> 

route定义的逻辑为从queue里取消息,然后进行一系列的处理(process(p0).process(p1)),<property name="transacted" value="true"/>的意思是通过这个jms进行的消息存取是有事务控制的.上面的route在process(p1)里抛出异常,txManager会进行rollback处理.(在activeMQ里,消息默认会redelivery到客户端6次,如果继续异常,消息会放到deadletter queue里(ActiveMQ.DLQ)),需要在AciveMQ的配置文件activemq.xml里配置如下:(non-persistent的queue的消息出错也转到dead letter queue)

<policyEntry queue=">">
<deadLetterStrategy>
   <sharedDeadLetterStrategy processNonPersistent="true" />
</deadLetterStrategy>

如果<property name="transacted" value="false"/>的话,消息在重发了6次后会丢失.

如果上面例子中的事务参与者是数据库的话,道理与之类似,只是配置的transaction manager不同,如:

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"/>

Camel里使用ActiveMQ JMS的例子可以参照 http://blog.csdn.net/kkdelta/article/details/7237096

2,Camel里的全局事务,一个route里有多个事务参与者,示例图如下:(图片来源于Camel in Action)


route的定义如下:
源码打印?

    public class XaTransaction extends RouteBuilder { 
        public void configure() throws Exception { 
            TProcessor1 p1 = new TProcessor1(); 
            from("jms:queue:TOOL.DEFAULT") 
            .transacted() 
            .log("+++ before database +++") 
            .bean(SQLBean.class, "toSql") 
            .to("jdbc:myDataSource") 
            .process(p1) 
            .log("+++ after database +++"); 
        } 
    } 
    public class SQLBean { 
        public String toSql(String str) { 
            //create table CamelTEST(msg varchar2(2000)); 
            StringBuilder sb = new StringBuilder(); 
            sb.append("INSERT INTO CamelTEST VALUES ('camel test')"); 
            return sb.toString(); 
        } 
    } 

route的逻辑是从queue里取消息,然后操作数据库,然后做后续其他操作(process(p1)),这里的process(p1)如果抛出异常的话,取消息和数据库操作都回滚,

如果整个route都成功完成的话,取消息和数据库操作提交.

这里用到JTA transaction manager是atomikos,相应的jar包可以从这里下载:http://download.csdn.net/detail/kkdelta/4056226

atomikos的主页 http://www.atomikos.com/Main/ProductsOverview

Spring的配置如下:
源码打印?

    <beans xmlns="http://www.springframework.org/schema/beans" 
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
           xmlns:broker="http://activemq.apache.org/schema/core" 
           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 
           http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core-5.2.0.xsd">    
        <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring"> 
            <package> 
                com.test.camel.transaction.xa 
            </package> 
        </camelContext> 
        <bean id="atomikosTransactionManager" 
              class="com.atomikos.icatch.jta.UserTransactionManager" 
              init-method="init" destroy-method="close" > 
            <!-- when close is called, should we force transactions to terminate or not? --> 
            <property name="forceShutdown" value="false"/> 
        </bean> 
        <!-- this is some atomikos setup you must do --> 
        <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp" > 
            <property name="transactionTimeout" value="300"/> 
        </bean> 
        <!-- this is some atomikos setup you must do --> 
        <bean id="connectionFactory" 
              class="com.atomikos.jms.AtomikosConnectionFactoryBean" > 
            <property name="uniqueResourceName" value="amq1"/> 
            <property name="xaConnectionFactory" ref="jmsXaConnectionFactory"/> 
        </bean> 
        <!-- this is the Spring JtaTransactionManager which under the hood uses Atomikos --> 
        <bean id="jtaTransactionManager" 
              class="org.springframework.transaction.jta.JtaTransactionManager" > 
            <property name="transactionManager" ref="atomikosTransactionManager"/> 
            <property name="userTransaction" ref="atomikosUserTransaction"/> 
        </bean> 
        <!-- Is the ConnectionFactory to connect to the JMS broker --> 
        <!-- notice how we must use the XA connection factory --> 
        <bean id="jmsXaConnectionFactory" class="org.apache.activemq.ActiveMQXAConnectionFactory" > 
            <property name="brokerURL" value="tcp://localhost:61616"/> 
        </bean> 
        <!-- define the activemq Camel component so we can integrate with the AMQ broker below --> 
        <bean id="jms" class="org.apache.activemq.camel.component.ActiveMQComponent" > 
            <property name="transacted" value="true"/> 
            <property name="transactionManager" ref="jtaTransactionManager"/> 
        </bean> 
       <bean id="myDataSource"  
          class="com.atomikos.jdbc.AtomikosDataSourceBean"  
          init-method="init" destroy-method="close">  
           <!-- set an arbitrary but unique name for the datasource -->  
          <property name="uniqueResourceName"><value>XADBMS</value></property>  
          <property name="xaDataSourceClassName">  
             <value>oracle.jdbc.xa.client.OracleXADataSource</value>  
          </property>  
          <property name="xaProperties">  
                    <props>  
                            <prop key="user">xxx</prop>  
                            <prop key="password">xxx</prop>  
                            <prop key="URL">jdbc:oracle:thin:@147.151.240.xxx:1521:orcl</prop> 
                    </props>  
          </property>     
          <property name="poolSize" value="1"/>  
       </bean>     
    </beans>

   
<project>  
      <modelVersion>4.0.0</modelVersion>  
      <groupId>my-osgi-bundles</groupId>  
      <artifactId>examplebundle</artifactId>  
      <packaging>bundle</packaging>    <!-- (1) -->  
      <version>1.0</version>  
      <name>Example Bundle</name>  
      <dependencies>  
        <dependency>  
          <groupId>org.apache.felix</groupId>  
          <artifactId>org.osgi.core</artifactId>  
          <version>1.0.0</version>  
        </dependency>  
      </dependencies>  
      <build>  
        <plugins>  
          <plugin>    <!-- (2) START -->  
            <groupId>org.apache.felix</groupId>  
            <artifactId>maven-bundle-plugin</artifactId>  
            <extensions>true</extensions>  
            <configuration>  
              <instructions>  
                <Export-Package>com.my.company.api</Export-Package>  
                <Private-Package>com.my.company.*</Private-Package>  
                <Bundle-Activator>com.my.company.Activator</Bundle-Activator>  
              </instructions>  
            </configuration>  
          </plugin>    <!-- (2) END -->  
        </plugins>  
      </build>  
    </project>
 

猜你喜欢

转载自qtlkw.iteye.com/blog/2233143