Apache Camel:RuntimeException之后没有回滚

时间:2014-04-07 13:23:12

标签: java jpa transactions apache-camel

我遇到Camel的交易管理问题。

在我的示例中,我从ZIP中提取XML文件,通过JAXB从xml中创建JPA实体并将其写入数据库。 然后我强制运行RuntimeException。

我的期望是插入的实体已回滚,但它们已经提交。

我在ZIP拆分器上设置了一个事务调用,以便处理所有包含文件或不处理任何文件。 聚合器负责在将数据库写入数据库之前汇集来自不同文件的元数据。

有人可以解释代码中缺少的内容或我对Camel交易管理的误解吗?

提前谢谢

阿德里安

...

  private final class AggregationStrategyImplementation implements AggregationStrategy {
        DocumentMetaDataContainer documentMetaDataContainer;

        public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
            if (oldExchange == null) {
                documentMetaDataContainer = (DocumentMetaDataContainer) newExchange.getIn()
                        .getBody();
                oldExchange = newExchange;
            } else {
                String header = String.valueOf(newExchange.getIn().getHeader("CamelFileName"));
                System.out.println("aggregating " + header);
                documentMetaDataContainer.putFileStreamToSpecificElement(header, newExchange
                        .getIn().getBody(byte[].class));

                if (isDone()) {
                    oldExchange.getOut().setHeader(Exchange.AGGREGATION_COMPLETE_ALL_GROUPS, true);
                }
            }
            return oldExchange;
        }

        public boolean isDone() {
            if (documentMetaDataContainer == null)
                return false;
            for (DocumentMetaData documentMetaData : documentMetaDataContainer
                    .getListOfDocumentMetaData()) {
                if (documentMetaData.getDocumentFile() == null)
                    return false;
            }
            return true;
        }
    }


    public void processImport() throws Exception {
        ApplicationContext springContext = new ClassPathXmlApplicationContext(
                "classpath:spring.xml");
      final CamelContext camelContext = SpringCamelContext.springCamelContext(springContext);

      RouteBuilder routeBuilder = new RouteBuilder() {
          private static final String inbox = "/Development/ppaFiles";                

          JAXBContext jaxbContext = JAXBContext.newInstance(new Class[] {
                  com.business.services.DocumentMetaDataContainer.class
                  });
          DataFormat jaxbDataFormat = new JaxbDataFormat(jaxbContext);

          public void configure() {
              from("file:"+inbox+"?consumer.delay=1000&noop=true")
                  .routeId("scanDirectory")
                  .choice()
                      .when(header("CamelFileName").regex("badb_(.)*.zip"))
                          .setHeader("msgId").simple("${header.CamelFileName}_${date:now:S}")
                          .log("processing zip file, aggregating by ${header.msgId}")
                          .to("direct:splitZip")
                  .end();


              from("direct:splitZip")
                  .routeId("splitZip")
                  .transacted()
                  .split(new ZipSplitter())
                  .streaming()
                  .choice()
                      .when(header("CamelFileName").regex("(.)*_files.xml")) // Meta File
                          .to("direct:toDocumentMetaData")
                      .otherwise() // PDF XML Files
                          .to("direct:toByteArray")
                          .end();

              from("direct:toByteArray")
                  .routeId("toByteArray")
                  .convertBodyTo(byte[].class)
                  .to("direct:aggregateZipEntries");


              from("direct:toDocumentMetaData")
                  .routeId("toDocumentMetaData")
                  .split()
                      // root tag name in xml file
                      .tokenizeXML("files")
                  .unmarshal(jaxbDataFormat)
                  .to("direct:aggregateZipEntries");


              from("direct:aggregateZipEntries")
                  .routeId("aggregateZipEntries")
                   // force to start with meta data file ('..._files.xml')
                  .resequence(simple("${header.CamelFileName.endsWith('_files.xml')}"))
                      .allowDuplicates()
                      .reverse()
                  .aggregate(new AggregationStrategyImplementation())
                      .header("msgId")
                      .completionTimeout(2000L)
                  .multicast()
                      .to("direct:saveDocumentMetaData", "direct:doErrorProcessing");


              from("direct:saveDocumentMetaData")
                  .routeId("saveDocumentMetaData")
                  .split(simple("${body.listOfDocumentMetaData}"))
                  .multicast()
                  .to("jpa://com.business.persistence.entities.DocumentMetaData"+
                            "?persistenceUnit=persistenceUnit"+
                            "&consumer.transacted=true"+
                            "&transactionManager=#transactionManager"+
                            "&flushOnSend=false")
                  .log("processDocumentMetaData: ${body.getName()}");


              from("direct:doErrorProcessing")
                  .routeId("doErrorProcessing")
                  .process(new Processor() {
                      public void process(Exchange exchange) throws Exception {
                              throw new RuntimeException("Error");
                      }
                  });
          }
      };

      camelContext.addRoutes(routeBuilder);

      camelContext.start();
      Thread.sleep(10000);
      camelContext.stop();
  }

  ...

1 个答案:

答案 0 :(得分:4)

似乎在" splitZip"中创建的交易路径不会延伸到" saveDocumentMetaData"中的保存事件。和" doErrorProcessing",perhaps due to using an aggregator without a persistent store。这就是" doErrorProcessing"中引发异常的原因。并没有导致" saveDocumentMetaData"回滚。

附上" saveDocumentMetaData"和#34; doErrorProcessing"在一个事务中为多播创建一个新事务:

// ...
  .aggregate(new AggregationStrategyImplementation())
    .header("msgId")
    .completionTimeout(2000L)
    .to("direct:persist");
// new transacted route
from("direct:persist")
  .routeId("persist")
  .transacted()
  .multicast()
    .to("direct:saveDocumentMetaData", "direct:importBalanceSheet");