java - 从关闭文件方法抛出 IOException 时如何管理事务(包括文件 IO)

标签 java file-io transactions spring-transactions

我最近开始使用 Spring 的数据源事务管理器。我现在有问题。 我的事务包括对数据库表的更新和对文件的写操作。

它工作正常,但我对文件 I/O 有一些疑问。正如您在下面看到的,我已经将我的 bean 的 openFile 和 closeFile 方法分别配置为 init 方法和 destroy 方法,这反过来又提供了这些方法,就像构造函数和析构函数一样被调用。如果文件没有正确关闭,一些记录可能没有成功写入output.txt文件,这意味着我也无法正确处理事务管理。

但是,我想回滚那些尚未附加到平面文件的数据库更新。使用我的解决方案,似乎不可能将 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);
    }                           
}
}   

最佳答案

一般来说,文件 IO 不是事务性的(某些特定于操作系统的功能除外)。

因此,您最好的办法是将打开和关闭操作移至 write() 方法,以便在事务内执行它们并在关闭失败时回滚事务。

但是请注意,在事务回滚的情况下,你不能回滚文件IO,这样在某些情况下你可以获得正确的文件和项目,而在数据库中这些项目没有被标记为已转移

要解决这个问题你可以尝试使用low-level transaction management support并尝试在回滚的情况下删除文件,但我认为它仍然不能提供强有力的一致性保证:

@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();                        
    }
}

关于java - 从关闭文件方法抛出 IOException 时如何管理事务(包括文件 IO),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5245682/

相关文章:

python - 通过python编辑配置文件

java - JPA EntityManager 在 @Transactional 方法之后阻塞

java - Spring @Transactional 失败后不回滚

c# - Azure 与 Azure SQL Server : ArgumentException: Value does not fall within the expected range

java - 如何制作更适合的fragment

c# - 为什么 System.IO.File 类是静态的

java - Protocol Buffer :如何在gradle的构建期间排除代码生成?

string - 用于保存的matlab迭代文件名

Java 易失变量、多线程

java - Apache XML-RPC 的奇怪行为