Spring Batch: java.io.IOException: flusso chiuso eccezione durante la combinazione di MultiResourceItemWriter e FlatFileItemWriter
-
05-07-2019 - |
Domanda
Ho un processo Spring Batch che prende un set di righe nel database e crea un numero di file flat da quelle righe, 10 righe per file. Per fare ciò, ho creato un processo Spring Batch, simile al seguente:
<batch:job id="springTest" job-repository="jobRepository" restartable="true">
<batch:step id="test">
<batch:tasklet>
<batch:chunk reader="itemReader" writer="multipleItemWriter" commit-interval="2" />
</batch:tasklet>
</batch:step>
</batch:job>
<bean id="itemReader" class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="resource" value="file:/temp/temp-input.txt" />
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.PassThroughLineMapper" />
</property>
</bean>
<bean id="multipleItemWriter" class="org.springframework.batch.item.file.MultiResourceItemWriter">
<property name="resource" value="file:/temp/temp-out" />
<property name="itemCountLimitPerResource" value="2" />
<property name="delegate">
<bean id="itemWriter" class="org.springframework.batch.item.file.FlatFileItemWriter">
<property name="lineAggregator">
<bean class="org.springframework.batch.item.file.transform.PassThroughLineAggregator" />
</property>
<property name="encoding" value="utf-8" />
<property name="headerCallback" ref="headerFooter" />
<property name="footerCallback" ref="headerFooter" />
</bean>
</property>
</bean>
<bean id="headerFooter" class="uk.co.farwell.spring.HeaderFooterCallback" />
L'esempio sopra riportato legge da un file flat e restituisce un file flat (per mostrare il problema). Nota commit-intervallo = 2 nel blocco e itemCountLimitPerResource = 2 in MultiResourceItemWriter.
HeaderFooterCallback effettua le seguenti operazioni:
public void writeHeader(Writer writer) throws IOException {
writer.write("file header\n");
}
public void writeFooter(Writer writer) throws IOException {
writer.write("file footer\n");
}
Devo essere in grado di specificare esattamente il numero di righe che compaiono nel file.
Per il seguente file di input:
foo1
foo2
foo3
Mi aspetto due file in uscita,
out.1:
file header
foo1
foo2
file footer
out.2:
file header
foo3
file footer
Quando corro con commit-intervallo = 2, ottengo un'eccezione:
2009-11-26 15:32:46,734 ERROR .support.TransactionSynchronizationUtils - TransactionSynchronization.afterCompletion threw exception
org.springframework.batch.support.transaction.FlushFailedException: Could not write to output buffer
at org.springframework.batch.support.transaction.TransactionAwareBufferedWriter$1.afterCompletion(TransactionAwareBufferedWriter.java:71)
at org.springframework.transaction.support.TransactionSynchronizationUtils.invokeAfterCompletion(TransactionSynchronizationUtils.java:157)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.invokeAfterCompletion(AbstractPlatformTransactionManager.java:974)
.
.
.
Caused by: java.io.IOException: Stream closed
at sun.nio.cs.StreamEncoder.ensureOpen(Unknown Source)
at sun.nio.cs.StreamEncoder.write(Unknown Source)
at sun.nio.cs.StreamEncoder.write(Unknown Source)
at java.io.Writer.write(Unknown Source)
at org.springframework.batch.support.transaction.TransactionAwareBufferedWriter$1.afterCompletion(TransactionAwareBufferedWriter.java:67).
Penso che questo sia un bug. Stranamente, i file sono i seguenti:
out.1:
file header
foo1
foo2
out.2:
file footer
Se ho due righe nel file di input, tutto funziona correttamente, ma più di due non funzionano. Se cambio l'intervallo di commit su 200, ottengo tre righe in un file, che non è il comportamento desiderato.
Se qualcuno potesse dirmi se sto facendo qualcosa di sbagliato, o se non come aggirare il problema, sarei molto grato.
Soluzione
In realtà, questo è un bug. Vedi http://jira.springframework.org/browse/BATCH-1452 .
La soluzione alternativa, secondo Dave Syer , è:
IOException è brutta. Un parziale soluzione alternativa è utilizzare il nuovo proprietà transazionale a FlatFileItemWriter, impostandolo su falso (BATCH-1449). Ma poi perdi Restartability (quindi se non è un problema sei pronto per andare). Ci proverò e risolverlo correttamente per 2.1.
Un'altra soluzione alternativa è pubblicare il processo i file in un passaggio separato (e non utilizzare i callback di intestazione / piè di pagina).
Il problema del conteggio (più di 2 articoli per file) è davvero separato: il scrittore multi-risorsa non è mai stato progettato per garantire la precisione numero di elementi per file, solo a traboccare se il limite viene violato. È possibile aprire un JIRA per un miglioramento se vuoi, una soluzione alternativa è da usare commit-interval = " 2 " nel tuo esempio (o più in generale un fattore del dimensione del file desiderata).
Altri suggerimenti
Considera, stai provando a leggere i dati da db e a scriverli in un file. In questo scenario, quando si scrivono i dati in un file, è necessario un oggetto da utilizzare in " HeaderFooterCallback " file. come si fa?