保持我的数据库和文件系统同步

时间:2013-03-15 18:57:30

标签: database file-storage

我正在研究一种将文件存储在文件系统中的软件,以及对数据库中这些文件的引用。因此,可以在数据库中查询上载的文件,而无需访问文件系统。从我在其他帖子中看到的内容,大多数人都说最好使用文件系统进行文件存储,而不是将二进制数据直接存储在数据库中作为BLOB。

所以现在我正在尝试理解设置它的最佳方法,以便数据库和文件系统保持同步,并且最终不会引用不存在的文件或文件占用文件系统中未引用的空间。以下是我正在考虑的两个选项。

选项1:首先添加文件参考

//Adds a reference to a file in the database
database.AddFileRef("newfile.txt"); 

//Stores the file in the file system
fileStorage.SaveFile("newfile.txt",dataStream); 

此选项会有问题,因为在实际文件之前添加了对文件的引用,因此另一个用户可能会在文件实际存储到系统之前尝试下载文件。尽管如此,因为在存储文件时可以使用主键值来预先创建对文件的引用。

选项2:首先存储文件

//Stores the file
fileStorage.SaveFile("newfile.txt",dataStream); 

//Adds a reference to the file in the database
//fails if reference file does not existing in file system
database.AddFileRef("newfile.txt"); 

此选项更好,但可以让某人将文件上传到从未引用过的系统。虽然这可以通过“清除”或“清理UFFileSystem”功能来修复,但删除任何未引用的文件。此选项也不允许使用数据库中的主键值存储文件。

选项3:待处理状态

//Adds a pending file reference to database
//pending files would be ignored by others
database.AddFileRef("newfile.txt"); 

//Stores the file, fails if there is no 
//matching pending file reference in the database
fileStorage.SaveFile("newfile.txt",dataStream); database

//marks the file reference as committed after file is uploaded
database.CommitFileRef("newfile.txt"); 

此选项允许在上载文件之前创建主键,但也阻止其他用户在上载文件之前获取对文件的引用。虽然,有可能永远不会上传文件,并且文件引用将被挂起。然而,从数据库中清除待处理的引用也是相当简单的。

我倾向于选项2,因为它很简单,我不必担心用户在上传之前尝试请求文件。存储是便宜的,所以如果我最终得到一些未引用的文件占用空间,它不是世界末日。但这似乎也是一个常见的问题,我想听听别人如何解决这个问题或者我应该做的其他考虑。

3 个答案:

答案 0 :(得分:2)

我想提出另一种选择。使文件名始终等于其内容的哈希值。然后,您可以随时安全地编写任何内容,前提是您在其他地方添加对它的引用之前。

由于内容永远不会改变,因此永远不会出现同步问题。

这为您提供免费的重复数据删除。删除变得更难。我建议每晚进行垃圾收集过程。

答案 1 :(得分:0)

数据库的实际用途是什么?如果它只是一个文件列表,我认为你根本不需要它,没有它可以省去你同步的麻烦。

如果您确信需要它,那么从技术角度来看,选项1和2完全相同 - 这两个资源可能不同步,您需要一个常规流程来再次合并它们。所以在这里你应该选择最适合应用的选项。

选项3没有任何优势,但使用更多资源。

请注意,使用哈希值,如usr所建议的那样,具有理论上的碰撞风险。而且,您还需要一个定期合并流程,如选项1和2。

另一个问题是如何处理正在进行的部分上传和上传。这里选项2可能有用,但您也可以使用在上传开始之前创建的第二个“flag”文件,并在上传完成时删除。这有助于您确定哪些上传已中止。

答案 2 :(得分:0)

为了弥补你提到的选项1 的缺点,我使用fileStorage.FileExists("newfile.txt");之类的东西,并过滤掉它返回负数的结果。

Python术语中:

import os
op = os.path

filter(lambda ref: op.exists(ref.path()), database.AllRefs())