Java 以事务方式写入文件
我正在尝试在springboot应用程序中写入/附加 我的要求是,如果在此过程中发生错误或出现任何错误,则回滚写入/追加操作 我有两种方法:Java 以事务方式写入文件,java,spring,spring-boot,file-io,opencsv,Java,Spring,Spring Boot,File Io,Opencsv,我正在尝试在springboot应用程序中写入/附加 我的要求是,如果在此过程中发生错误或出现任何错误,则回滚写入/追加操作 我有两种方法: 使用openCSV库写入csv文件(可根据需要正常工作,即事务行为) II。我还使用nioFileChannel实现了同样的功能: public String writeStudentsToFlatFile1(List<Student> students, String filePath){ BufferedWriter bw= F
FileChannel实现了同样的功能:
public String writeStudentsToFlatFile1(List<Student> students, String filePath){
BufferedWriter bw= Files.newBufferedWriter(Paths.get(filePath));
StringBuilder strb = new StringBuilder();
students.forEach(student -> {
strb.append(student.toString()).append(System.lineSeparator());
});
bw.write(strb.toString());
bw.close();
return "OK";
}
public String writeStudentsToFlatFile2(List<Student> students, String filePath){
RandomAccessFile file = new RandomAccessFile(filePath, "rw");
FileChannel channel = file.getChannel();
StringBuilder strb = new StringBuilder();
for (Student student : students){
strb.append(student.toString()).append(System.lineSeparator());
}
ByteBuffer buffer = ByteBuffer.wrap(strb.toString().getBytes(StandardCharsets.UTF_8));
channel.position(channel.size());
channel.write(buffer);
channel.close();
file.close();
return "OK";
}
如果在同一文件路径的循环中调用此方法writeStudentsToFlatFile3
,则在第一次迭代后会抛出此错误:
java.lang.NullPointerException:org.springframework.batch.support.transaction.TransactionWarebufferedWriter.close(TransactionWarebufferedWriter.java:189)~[spring-batch-infrastructure-4.2.4.RELEASE.jar:4.2.4.RELEASE]
它可能与使用Runnable
参数关闭资源有关。我认为您将输出缓冲的效果与“事务行为”混淆了。OpenCSV或BufferedWriter没有事务性。是什么让你认为是这样的?另外,您希望导致回滚的“错误”有哪些?如果希望使用简单文件回滚,则需要在开始时跟踪文件输出位置,然后截断回该位置以执行回滚,从而自己实现。作为补充说明,使用FileChannel
可能更方便事务性使用case@JimGarrison我的错。我可能用了不正确的术语。简而言之,我的要求是->要么将整个列表写入(追加)文件,要么不写入列表的任何元素(以防出现异常)。原子性。我已经用当前使用的解决方法更新了这个问题。问题是代码和文件之间有好几层,其中任何一层都可能由于各种原因而失败。如果您想使写原子化,您必须使用现有的原子库类(不清楚Spring类在Javadoc中做了什么),或者实现您自己的:save file指针;写若异常截断回旧文件指针。如果您的程序被用户或操作系统kill-9
ed破坏,您仍然可能最终被破坏。为了保证原子性,您必须将文件指针保留在自己的文件中,并根据打开时的实际文件长度进行验证,以检测此情况。简而言之,文件系统中的原子性很难实现。
public String writeStudentsToFlatFile1(List<Student> students, String filePath){
BufferedWriter bw= Files.newBufferedWriter(Paths.get(filePath));
StringBuilder strb = new StringBuilder();
students.forEach(student -> {
strb.append(student.toString()).append(System.lineSeparator());
});
bw.write(strb.toString());
bw.close();
return "OK";
}
public String writeStudentsToFlatFile2(List<Student> students, String filePath){
RandomAccessFile file = new RandomAccessFile(filePath, "rw");
FileChannel channel = file.getChannel();
StringBuilder strb = new StringBuilder();
for (Student student : students){
strb.append(student.toString()).append(System.lineSeparator());
}
ByteBuffer buffer = ByteBuffer.wrap(strb.toString().getBytes(StandardCharsets.UTF_8));
channel.position(channel.size());
channel.write(buffer);
channel.close();
file.close();
return "OK";
}
public String writeStudentsToFlatFile3(List<Student> list, String filePath){
RandomAccessFile file = new RandomAccessFile(filePath, "rw");
FileChannel channel = file.getChannel();
StringBuilder strb = new StringBuilder();
TransactionAwareBufferedWriter writer = new TransactionAwareBufferedWriter(channel, null);
for (Student student : list){
strb.append(element.toString()).append(System.lineSeparator());
}
writer.append(strb.toString());
writer.close();
channel.close();
file.close();
return "OK";
}