2011-03-09 12 views
5

Ho recentemente iniziato a utilizzare Gestore transazioni di origine dati di Spring. Ho un problema ora. La mia transazione include aggiornamenti a una tabella DB e un'operazione di scrittura su un file.Come gestire la transazione (che include File IO) quando viene lanciata una IOException dal metodo del file chiuso

Funziona bene ma ho qualche dubbio sull'I/O dei file. Come vedete in seguito, ho configurato i metodi openFile e closeFile del mio bean rispettivamente come metodo init e destroy-metodo, che a sua volta fornisce quei metodi per essere chiamati proprio come un costitutore e un distruttore. Se il file non viene chiuso correttamente, alcuni dei record potrebbero non essere stati scritti correttamente nel file output.txt, il che significa che non sono stato in grado di gestire correttamente anche la gestione delle transazioni.

Tuttavia, mi piacerebbe eseguire il rollback di quegli aggiornamenti DB che non sono stati aggiunti al file flat. Con la mia soluzione, sembra impossibile aggiungere il metodo fileClose alla transazione. Qualcuno sa come implementare correttamente questa azione desiderata?

Ogni suggerimento sarà molto apprezzato

<!--XML CONFIGURATION --> 
<bean id="myFileWriter" class="com.job.step.ItemFileWriter" init-method="openFile" destroy-method="closeFile"> 
    <property name="jdbcTemplate" ref="jdbcTemplateProduct"/> 
</bean> 

public class ItemFileWriter implements ItemWriter<Item> { 
private static final Logger log = Logger.getLogger(ItemFileWriter.class); 
private BufferedWriter bw = null; 
public void openFile() throws IOException { 
    try { 
     bw = new BufferedWriter(new FileWriter("C:\\output.txt")); 
    } catch (IOException e) {   
     //log.error(e); 
     throw e; 
    }  
} 
public void closeFile() throws IOException { 
    if (bw != null) { 
     try { 
      bw.close(); 
     } catch (IOException e) { 
      log.error(e); 
      throw e; 
     } 
    } 
} 

@Transactional(rollbackFor = IOException.class) 
public void write(List<? extends Item> itemList) throws IOException 
{    
    for (Iterator<? extends Item> iterator = itemList.iterator(); iterator.hasNext();) { 
     Item item = (Item) iterator.next(); 

     String updateRtlnOutbound = "UPDATE SAMPLESCHEMA.SAMPLETABLE SET STATUS='TRANSFERRED' WHERE ID = ?"; 
     jdbcTemplate.update(updateRtlnOutbound, new Object[]{item.getID()}); 

     String item = String.format("%09d\n", item.customerNumber); 
     bw.write(item); 
    }       
} 
} 

risposta

3

In generale, il file IO non è transazionale (ad eccezione di alcune caratteristiche specifiche del sistema operativo).

Quindi, la cosa migliore che puoi fare è spostare l'operazione di apertura e chiusura al metodo write(), per eseguirli all'interno di una transazione e ripristinare la transazione se la chiusura fallisce.

Nota, tuttavia, non è possibile eseguire il rollback del file I/O in caso di rollback della transazione, in modo che in alcune circostanze sia possibile ottenere il file corretto con gli articoli, mentre nel database questi elementi non sono contrassegnati come TRANSFERRED.

Per sove questo problema si può provare a utilizzare low-level transaction management support e cercare di eliminare il file, nel caso di rollback, ma penso che ancora non è in grado di fornire forti garanzie di coerenza:

@Transactional(rollbackFor = IOException.class) 
public void write(List<? extends Item> itemList) throws IOException 
{     
    openFile(); 
    TransactionSynchronizationManager().registerSynchronization(new TransactionSynchronizationAdapter() { 
     public void afterCompletion(int status) { 
      if (status = STATUS_ROLLED_BACK) { 
       // try to delete the file 
      } 
     } 
    }); 

    try { 
     ... 
    } finally { 
     closeFile();       
    } 
} 
2

Si sta facendo operazioni su due sistemi diversi: file system e database. In genere, le transazioni XA ci facilitano la combinazione di diversi sistemi transazionali in un'unica transazione.

La maggior parte dei database può essere creata per partecipare alle transazioni XA. Per il file system è possibile utilizzare XADisk per abilitare XA. Una volta abilitato XA su entrambi i database (tramite la corretta configurazione dell'origine dati) e il file system (tramite xadisk), si può essere certi che sia il commit di file e database sia di rollback di entrambi.

Problemi correlati