简体   繁体   中英

Safe file-based data persistance in Java EE

Is it possible to have a Java EE application (based on Spring Framework, running in Tomcat container) persisting its data in a file on the server?

The scenario is as follows: I have a class with an int field (read from ?? during startup). I want to save it to a file in a safe manner (as safe as possible, meaning surviving server crash would be appreciated). Is it possible (besides naive file reading/writing)

Kind regards, q

Really the only "safe" way to do it is to rely on the underlying file system.

Simply:

public void saveThing(Serializable thing, String fileName) throws Exception {
    String tempFileName = fileName + "_tmp";
    File tempFile = new File(tempFileName);
    FileOutputStream fos = new FileOutputStream(tempFile);        
    FileDescriptor fd = fos.getFD();
    ObjectOutputStream oos = new ObjectOutputStream(fos);
    oos.writeObject(thing);
    oos.flush();
    fd.sync();
    oos.close();
    f.renameTo(fileName);
}

What's happening here is first we're writing the file to a temporary file. This ensures that the entire file write succeeds without damaging the original file (for example, if you run out of disk space, the original will be retained as this routine will not finish). However if this routine fails, the lingering temp file will remain, and will need to be cleaned up later.

Once we've written the file, we force the OS to flush any pending writes to the actual disk. Many systems buffer file system writes to ram, and "eventually" write them out to disk. This is for obvious performance reasons. However, should the system crash or lose power between when you closed the file, and the OS decides to flush the writes, you can potentially lose data. This sync is an EXPENSIVE operation.

Finally, once we are sure that we have written the file, and that it is committed to disk (as sure as we can be anyway), we then RENAME the temp file to the actual file name.

Renaming a file on the file system is an atomic operation. It's can't partially fail. It either works, or it doesn't. If the two files are on the same file system, the rename is near instantaneous since it simply updates some file system information. If the two are on separate file systems, then the new file must be copied first to the new file system, and then renamed. I ASSUME this is how it is done, I never tested this. I tend to stick to the same file system and avoid the question completely.

This process ensures that the file will be updated, under the correct name, completely, "all at once". The file (under its correct name) never only "partially exists", which is what would happen if you were to simply overwrite the existing file.

Finally, on Windows you may have a problem if there is contention for the original file, since Windows will not delete a file that is opened by something else. Unix has no problem doing this, but Windows does. So you need to ensure through some external means that you have sole access to the file before doing this rename procedure.

The short answer is yes. I actually had to do just that for a project that I did with a university a while back. I posted the code for it on my git hub: Speak To Me project . In that Web app, I persisted user data to file in plain text so it was both human readable and easy to for objects to reinitialize themselves.

So readers of this question might be wondering why I didn't use a database for these purposes. Well the university that I was working with didn't want to support one. As well, this app had really low traffic; it is a research prototype for testing search interfaces so it was only used for user studies. Finally, because of the nature of the application, persisting to file keep things really simple. In fact, the data files were later used for post study analyses. Plus it kept the option open for students who were not great coders to get their feet wet (that... never happened).

Anyhow, my recommendation is that if you are just persisting simple values, then plain text will be fine. If your data has any amount of complexity, then use JSON. XML is a bit heavyweight and really should only be used if your application is large but in that scenario, you shouldn't be persisting to file.

It may be on overkill for your situation, but you could use HSQLDB . You can configure it to persist in a file.

For a simpler solution, you can always write/read from a file. Some issues worth of consideration:

  • Use JNDI or a system variable to store the name and path of the file.
  • Make sure that the user that runs the server has read/write access to the file.
  • Other than that you can use standard Java File operations

您可以使用Java中的可序列化接口来创建可以从磁盘保存和重新加载的持久对象。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM