Spring Batch: java.io.IOException: exception de flux fermé lors de la combinaison de MultiResourceItemWriter et de FlatFileItemWriter
-
05-07-2019 - |
Question
J'ai un processus Spring Batch qui prend un ensemble de lignes dans la base de données et crée un certain nombre de fichiers plats à partir de ces lignes, 10 lignes par fichier. Pour ce faire, j'ai créé un processus Spring Batch, similaire à celui-ci:
<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'exemple ci-dessus lit à partir d'un fichier plat et est exporté dans un fichier plat (pour montrer le problème). Notez que commit-interval = 2 dans le bloc et itemCountLimitPerResource = 2 dans MultiResourceItemWriter.
HeaderFooterCallback effectue les opérations suivantes:
public void writeHeader(Writer writer) throws IOException {
writer.write("file header\n");
}
public void writeFooter(Writer writer) throws IOException {
writer.write("file footer\n");
}
Je dois pouvoir spécifier exactement le nombre de lignes qui apparaissent dans le fichier.
Pour le fichier d'entrée suivant:
foo1
foo2
foo3
Je m'attendrais à deux fichiers en sortie,
out.1:
file header
foo1
foo2
file footer
out.2:
file header
foo3
file footer
Lorsque j'exécute avec commit-interval = 2, j'obtiens une exception:
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).
Je pense que c'est un bug. Bizarrement, les fichiers sont les suivants:
out.1:
file header
foo1
foo2
out.2:
file footer
Si le fichier d'entrée contient deux lignes, tout fonctionne correctement, mais plus de deux ne fonctionnent pas. Si je modifie l'intervalle de validation à 200, le fichier contient trois lignes, ce qui n'est pas le comportement souhaité.
Si quelqu'un pouvait me dire si je fais quelque chose de mal ou sinon comment résoudre le problème, je vous en serais très reconnaissant.
La solution
En fait, c'est un bug. Voir http://jira.springframework.org/browse/BATCH-1452 . / p>
La solution de contournement, selon Dave Syer , est la suivante:
L'exception IOException est méchante. Une partielle La solution consiste à utiliser le nouveau propriété transactionnelle dans FlatFileItemWriter, en le définissant à faux (BATCH-1449). Mais alors tu perds possibilité de redémarrage (donc si ce n'est pas un vous êtes prêt à partir). j'essaierai et corrigez-le correctement pour 2.1.
Une autre solution consiste à poster un processus les fichiers dans une étape séparée (et non utilisez les rappels d’en-tête / pied de page).
Le problème de comptage (plus de 2 éléments par fichier) est vraiment séparé - le écrivain multi-ressources n'a jamais été conçu pour garantir la précision nombre d'éléments par fichier, uniquement pour débordement si la limite est dépassée. Vous pouvez ouvrir une JIRA pour une amélioration si vous voulez, une solution consiste à utiliser commit-interval = " 2 " dans votre exemple (ou plus généralement un facteur de taille de fichier souhaitée).
Autres conseils
Tenez compte du fait que vous essayez de lire les données de la base de données et de les écrire dans un fichier. Dans ce scénario, lorsque vous écrivez les données dans un fichier, vous devez utiliser un objet dans "HeaderFooterCallback". fichier. comment faites-vous cela?