如何使用 Spring 无条件批量写入每个读取行的多个表
How to write to multiple tables per read row using Spring Batch with no conditions
我在这个论坛中找到了很多使用多个作者的例子。大多数(如果不是全部)答案都集中在 CompositeItemWriter 和 ClassifierItemWriter 上。
业务需求:从输入文件中读取一行。这一行会包含多个字段(超过50个)需要写到自己的数据库表中(理论上代表不同的classes)。
----- claimwriter(write to claim table)
/
/
claimlineitemprocessor -----
\
\
----- pharmacywriter(write to pharmacy table)
我使用字段集映射器创建了表示索赔行 (ClaimLine) 的对象。大多数字段是对文件中数据的简单映射,但少数需要更改格式或相关字段映射逻辑。
基本项目编写器代码如下所示:
@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;
};
在创建自定义源提供程序时,他们每个人似乎都在期待,因为那是 class 已经映射到输入行并包含我想发送到相应表的值。
这基本上就是我现在无法使用 CompositeItemWriter 的原因,因为我正在尝试将单个对象转换为两个不同的对象。 ClassifierCompositeItemWriter 的工作方式类似于路由器,并将其发送到特定于条件的路径,这不是我想要做的。
作为参考,我尝试用 Spring 集成做一些类似的事情,但也遇到了类似的障碍。
感谢任何帮助。
我相信@Hansjoerg 和@Luca 的评论对这个问题提供了有价值的回答,并且在研究之前和研究期间进行了研究以获得答案。
我能够通过继续使用 ItemSqlParameterSourceProvider 来解决这个问题,代码如下。当我最初探索如何使用这个 class 及其方法时,我的想法是我仍然只是在 ClaimLine class.
上操作
真正发生的是该方法正在接收作者的 class 并且您正在设置您使用 setSQL(String sql).通过使用 ItemSqlParameterSourceProvider,您正在为 put 语句使用 SQL 中的命名参数。以下代码仅显示索赔代码。药房也差不多。
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 调用中。
可以用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>
这段代码更新了 2 个表,对我有用。
也许我的回答是你的例外。我也看到了同样的问题,我用 classifierCompositeWriter
来解决它。我在我的项目中定义了我的分类器,如你所见,你可以决定你应该在你的逻辑中使用哪个编写器。例如,在我的逻辑中
if(baseEntity instanceof Product){
return productItemWriter;
}else {
return otherItemWriter;
}
祝你好运。
我在这个论坛中找到了很多使用多个作者的例子。大多数(如果不是全部)答案都集中在 CompositeItemWriter 和 ClassifierItemWriter 上。
业务需求:从输入文件中读取一行。这一行会包含多个字段(超过50个)需要写到自己的数据库表中(理论上代表不同的classes)。
----- claimwriter(write to claim table)
/
/
claimlineitemprocessor -----
\
\
----- pharmacywriter(write to pharmacy table)
我使用字段集映射器创建了表示索赔行 (ClaimLine) 的对象。大多数字段是对文件中数据的简单映射,但少数需要更改格式或相关字段映射逻辑。
基本项目编写器代码如下所示:
@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;
};
在创建自定义源提供程序时,他们每个人似乎都在期待,因为那是 class 已经映射到输入行并包含我想发送到相应表的值。
这基本上就是我现在无法使用 CompositeItemWriter 的原因,因为我正在尝试将单个对象转换为两个不同的对象。 ClassifierCompositeItemWriter 的工作方式类似于路由器,并将其发送到特定于条件的路径,这不是我想要做的。
作为参考,我尝试用 Spring 集成做一些类似的事情,但也遇到了类似的障碍。
感谢任何帮助。
我相信@Hansjoerg 和@Luca 的评论对这个问题提供了有价值的回答,并且在研究之前和研究期间进行了研究以获得答案。
我能够通过继续使用 ItemSqlParameterSourceProvider 来解决这个问题,代码如下。当我最初探索如何使用这个 class 及其方法时,我的想法是我仍然只是在 ClaimLine class.
上操作真正发生的是该方法正在接收作者的 class 并且您正在设置您使用 setSQL(String sql).通过使用 ItemSqlParameterSourceProvider,您正在为 put 语句使用 SQL 中的命名参数。以下代码仅显示索赔代码。药房也差不多。
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 调用中。
可以用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>
这段代码更新了 2 个表,对我有用。
也许我的回答是你的例外。我也看到了同样的问题,我用 classifierCompositeWriter
来解决它。我在我的项目中定义了我的分类器,如你所见,你可以决定你应该在你的逻辑中使用哪个编写器。例如,在我的逻辑中
if(baseEntity instanceof Product){
return productItemWriter;
}else {
return otherItemWriter;
}
祝你好运。