我遇到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();
}
...
答案 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");