8

私は最近、Spring の Data Source Transaction Manager を使い始めました。今問題があります。私のトランザクションには、DB テーブルへの更新とファイルへの書き込み操作が含まれます。

正常に動作しますが、ファイル I/O について疑問があります。以下に示すように、Bean の openFile メソッドと closeFile メソッドをそれぞれ init-method と destroy-method として構成しました。これにより、コンストラクターとデストラクターのように呼び出されるメソッドが提供されます。ファイルが適切に閉じられていない場合、一部のレコードが output.txt ファイルに正常に書き込まれていない可能性があります。これは、トランザクション管理も適切に処理できていないことを意味します。

ただし、フラット ファイルに追加されていない DB 更新をロールバックしたいと考えています。私の解決策では、 fileClose メソッドをトランザクションに追加することは不可能に見えます。この望ましいアクションを適切に実装する方法を知っている人はいますか?

どんな提案でも大歓迎です

<!--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);
    }                           
}
}   
4

2 に答える 2

4

一般的に言えば、ファイル IO はトランザクショナルではありません (一部の OS 固有の機能を除く)。

したがって、できることは、オープンとクローズの操作をwrite()メソッドに移動して、トランザクション内で実行し、クローズが失敗した場合にトランザクションをロールバックすることです。

ただし、トランザクション ロールバックの場合はファイル IO をロールバックできないことに注意してください。そのため、状況によってはアイテムを含む正しいファイルを取得できますが、データベースではこれらのアイテムは としてマークされませんTRANSFERRED

この問題を解決するには、低レベルのトランザクション管理サポートを使用して、ロールバックの場合にファイルを削除しようとすることができますが、それでも一貫性の強力な保証は提供できないと思います。

@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();                        
    }
}
于 2011-03-09T12:43:46.593 に答える
3

ファイルシステムとデータベースの 2 つの異なるシステムで操作を行っています。通常、XA トランザクションを使用すると、さまざまなトランザクション システムを 1 つのトランザクションに簡単に組み合わせることができます。

ほとんどのデータベースは、XA トランザクションに参加させることができます。ファイル システムの場合、XADiskを使用して XA を有効にできます。データベース (データ ソースの適切な構成を介して) とファイル システム (xadisk を介して) の両方で XA を有効にすると、ファイルとデータベースの両方の操作が確実にコミットされるか、両方がロールバックされます。

于 2012-02-10T19:10:45.197 に答える