Java 以事务方式写入文件

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

我正在尝试在springboot应用程序中写入/附加

我的要求是,如果在此过程中发生错误或出现任何错误,则回滚写入/追加操作

我有两种方法:

  • 使用openCSV库写入csv文件(可根据需要正常工作,即事务行为)
  • II。我还使用nio
    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";
    }