当前位置: 首页 > 知识库问答 >
问题:

如何在没有条件的情况下使用Spring批处理在每个读取行中写入多个表

长孙景焕
2023-03-14

我在这个论坛上找到了许多使用多个作家的例子。大多数,如果不是全部的话,答案集中在复合作者和分类作者身上。

业务需求:从输入文件中读取一行。这一行将包含多个字段(超过50个),需要写入它们自己的数据库表(理论上代表不同的类)。

                               ----- claimwriter(write to claim table)
                              /
                             /
claimlineitemprocessor  -----
                             \
                              \
                               ----- pharmacywriter(write to pharmacy table)

我使用了一个字段集映射器来创建表示索赔行(ClaimLine)的对象。大多数字段是对文件中数据的简单映射,但少数字段需要更改其格式或相关字段映射逻辑。

基本item writer代码如下所示:

@SuppressWarnings({ "unchecked", "rawtypes" })
@Bean
public ItemWriter<ClaimLine> writer() {
    CompositeItemWriter<ClaimLine> cWriter = new CompositeItemWriter<ClaimLine>();

    JdbcBatchItemWriter claimWriter = new JdbcBatchItemWriter();
    claimWriter.setItemSqlParameterSourceProvider(new ClaimItemSqlParameterSourceProvider());
    claimWriter.setSql( // would like to insert into pharmacy table);
    claimWriter.setDataSource(dataSource);
    claimWriter.afterPropertiesSet();

    JdbcBatchItemWriter pharmacyWriter = new JdbcBatchItemWriter();
    pharmacyWriter.setItemSqlParameterSourceProvider(new PharmacyItemSqlParameterSourceProvider());
    pharmacyWriter.setSql( // would like to insert into pharmacy table);
    pharmacyWriter.setDataSource(dataSource);
    pharmacyWriter.afterPropertiesSet();

    List<ItemWriter<? super ClaimLine>> mWriter = new ArrayList<ItemWriter<? super ClaimLine>>();
    mWriter.add(claimWriter); 
    mWriter.add(pharmacyWriter);
    cWriter.setDelegates(mWriter);

    // other code

    return cWriter;
};

在创建自定义源提供程序时,它们中的每一个似乎都是预期的,因为这个类已经映射到输入行,并且包含我想要发送到各个表的值。

这就是我现在陷入困境的原因,我认为我不能使用CompositeItemWriter,因为我试图将一个对象转换为两个不同的对象。ClassifierCompositeItemWriter的工作原理类似于路由器,它沿着特定于某个条件的路径发送,这不是我想要做的。

作为参考,我尝试过用Spring集成做类似的事情,但也遇到了类似的障碍。

感谢您的帮助。

共有3个答案

扶杜吟
2023-03-14

也许我的答案是你的例外。我也看到了同样的问题,我使用了classifierCompositeWriter来解决它。我在我的项目中定义了分类器,正如你所见,你可以决定在逻辑中使用哪个编写器。例如,在我的逻辑中

if(baseEntity instanceof Product){ 
    return productItemWriter;
}else {
    return otherItemWriter;
}

祝你好运。

万俟财
2023-03-14

你可以用chain写多个表,

<int:chain input-channel="processTransactionChannel"
		output-channel="processedItems">
		<int:header-enricher>
			<int:header name="savePayload" expression="payload" />
		</int:header-enricher>

		<int-jpa:updating-outbound-gateway
			auto-startup="true"
			native-query="insert into  TableOne values( :transactionStatus ,bank_Reference_Number = :bankReferenceNumber )"
			entity-manager="entityManager" 
			use-payload-as-parameter-source="false">
			<int-jpa:transactional />
			<int-jpa:parameter name="transactionStatus"
				expression="payload['transactionStatus']" />
			<int-jpa:parameter name="bankReferenceNumber"
				expression="payload['bankReferenceNumber']" />

		</int-jpa:updating-outbound-gateway>

		<int:transformer expression="headers.savePayload" />

		
		<int-jpa:updating-outbound-gateway
			native-query="insert 
 						into PARTNER_RESPONSE_DETAILS(PARTNER_ID,BANK_REFERENCE_NUMBER,REQUEST_STRING,RESPONSE_STRING)  
  						values (:partnerId,:bankRefNumber,:requestString,:responseString)"
			entity-manager="entityManager">
			<int-jpa:transactional />
			<int-jpa:parameter name="partnerId" expression="payload['partnerId']" />
			<int-jpa:parameter name="bankRefNumber" expression="payload['bankRefNumber']" />
			<int-jpa:parameter name="requestString" expression="payload['requestString']" />
			<int-jpa:parameter name="responseString"
				expression="payload['responseString']" />
			<int-jpa:parameter name="transactionStatus"
				expression="payload['transactionStatus']" />
			<int-jpa:parameter name="bankReferenceNumber"
				expression="payload['bankReferenceNumber']" />

		</int-jpa:updating-outbound-gateway>

		<int:transformer expression="headers.savePayload" />


	</int:chain>
黄朗
2023-03-14

我相信@Hansjoerg和@Luca的评论对这个问题提供了有价值的回答,并在研究之前和期间进行了研究以寻找答案。

我通过继续使用ItemSqlParameterSourceProvider解决了这个问题,代码如下。当我最初探索如何使用这个类及其方法时,我的想法是,我仍然只在ClaimLine类上操作。

真正发生的情况是,方法从编写器接收类,并且您正在设置用setSQL(String sql)设置的SQL语句的值。使用ItemSqlParameterSourceProvider,您将使用SQL中的命名参数来表示put语句。下面的代码仅显示声明的代码。药房将类似。

public class ClaimItemSqlParameterSourceProvider implements ItemSqlParameterSourceProvider<ClaimLine> {

    @SuppressWarnings({ "serial"})
    @Override
    public SqlParameterSource createSqlParameterSource(final ClaimLine item) {
        return new MapSqlParameterSource(new HashMap<String, Object>() {
            {
                put("rxclaimid", item.getRxClaimID());
                ...
                // many more
            }
        });
    }
}

定义条目编写器可能也解决了这个问题,但似乎需要更多的编码来支持它。最后,对于这种情况,使用ItemPreparedStatementSetter或ItemSqlParameterSourceProvider都可以。我们选择后者的主要原因是,参数的名称是明确的,而不是通过索引值(1、2、3等)和使用“?”来访问参数值在setSQL调用中。

 类似资料:
  • 我正在尝试在没有项目编写器的情况下使用下面的配置来配置spring批处理步骤。然而,我错误地说writer元素既没有'writer'属性,也没有元素。 我浏览了链接spring批处理:没有ItemWriter的Tasklet。但无法解决问题。有人能告诉我在我提到的代码片段中要做的具体更改吗

  • CompositeItemWriter:当我需要将项目平均地分给Writer时,似乎会将所有读取的项目传递给所有的Writer。 BacktoBackPatternClassifier:我并不真正需要分类器,因为我是均匀地拆分项目。 有没有另一种方式,让一个读者和多个作者? 或者我可以在Writer中手动创建线程?

  • 我刚开始使用Spring批处理,我有一个特殊问题。我希望使用从3个不同的jpa查询中获取结果,并分别处理它们,然后使用将它们写入一个统一的XML文件。 对于eg,生成的XML看起来像是,

  • 我有从多个文件读取并写入多个文件的Spring批处理配置。是否可以只写入从多个读取的一个文件。假设我收到巨大的XML文件,我将XML拆分为小文件并使用分区器并行读取小文件。但我需要将从不同的小xml文件读取的所有数据写入一个输出文件。Spring批处理是否可以做到这一点?我知道通过使写入器同步是可能的,但我正在寻找任何其他可能的方式作业配置 我得到错误组织。springframework。一批项目

  • 我需要从多个目录中读取文件,并处理数据并将其存储到DB中。目前我正在使用块多资源阅读器,它适用于1个目录。但现在我必须从多个目录中读取文件。如何使用Spring批处理来做到这一点

  • 矩阵示例是: 它通过以下方式保存到文件中 write.table (Aexample,file = "~/R/Aexample ",row.names = FALSE,col . names = FALSE); 然后我读到 Aexample=as.matrix(read.table(file="~/R/Aexample")); 但是结果总是有我不想要的V1 V2 V3 V4列名: 保存Aexamp