问题描述
我最近开始使用Spring的数据源事务管理器.我现在有问题.我的事务包括对数据库表的更新和对文件的写操作.
I've recently begun using Spring's Data Source Transaction Manager. I have a problem now.My transaction includes updates to a DB table and a write operation to a file.
它工作正常,但是我对文件I/O有一些疑问.如下所示,我已将bean的openFile和closeFile方法分别配置为init-method和destroy-method,它们依次提供了那些调用方法,就像构造器和析构器一样.如果未正确关闭文件,则某些记录可能未成功写入output.txt文件,这意味着我也无法正确处理事务管理.
It works fine but I have some doubts about file I/O. As you see below, I have configured openFile and closeFile methods of my bean as the init-method and the destroy-method respectively, which in turn provides those methods to be called just like a constuructor and a destructor. If the file is not closed properly, some of the records may not have successfully been written to the output.txt file which means that I have not been able to handle transaction management properly as well.
但是,我想回滚那些尚未附加到平面文件的数据库更新.使用我的解决方案,似乎无法将fileClose方法添加到事务中.有人知道如何正确地执行此期望的操作吗?
However, I'd like to rollback those DB updates which have not been appended to the flat file. With my solution, it looks impossible to add the fileClose method to the transaction. Does anyone know how to implement this desired action properly?
任何建议将不胜感激
<!--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不是事务性的(某些操作系统特定的功能除外).
Generally speaking, file IO is not transactional (except for some OS-specific features).
因此,最好的办法是将打开和关闭操作移至 write()
方法,以便在事务中执行它们,并在关闭失败时回滚事务.
So, the best you can do is to move open and close operation to write()
method, in order to execute them inside a transaction and rollback the transaction if closing fails.
但是请注意,在事务回滚的情况下,您不能回滚文件IO,因此在某些情况下,您可以获得带有项目的正确文件,而在数据库中,这些项目未标记为转移
.
Note, however, that you can't rollback the file IO in the case of transaction rollback, so that under some circumstances you can get the correct file with items, whereas in the database these items are not marked as TRANSFERRED
.
要解决此问题,您可以尝试使用低级事务管理支持,并在回滚的情况下尝试删除该文件,但我认为它仍然不能提供强有力的一致性保证:
To sove this problem you can try to use low-level transaction management support and try to delete the file in the case of rollback, but I think it still can't provide strong guarantees of consistency:
@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();
}
}
这篇关于从关闭文件方法抛出IOException时如何管理事务(包括文件IO)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!