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

25

我正在开发一款软件,它将文件存储在文件系统中,并在数据库中引用这些文件。因此,可以在不访问文件系统的情况下,在数据库中查询上传的文件。从我在其他文章中读到的内容来看,大多数人都认为使用文件系统进行文件存储比直接在数据库中存储二进制数据(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"); 

这个选项更好,但有可能会让某人上传一个从未被引用的文件到系统中。虽然可以通过“清除”或“清理文件系统”函数来删除任何未被引用的文件来解决这个问题。此选项也不允许使用数据库主键值来存储文件。

选项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
非常聪明的问题。许多人从未考虑过不同数据存储之间的一致性。 - usr
3个回答

4
我想提出另一个选项。将文件名始终设置为其内容的哈希值。然后,只要在其他地方添加引用之前编写任何内容,就可以随时安全地编写 任何内容
由于内容永远不会更改,因此永远不会出现同步问题。
这为您提供了免费的去重。但是删除变得更加困难。我建议进行夜间垃圾收集处理。

你能详细说明一下吗?我会从文件中获取哈希码,然后使用该码确定文件在文件系统中的存储方式。那么数据库将使用哈希码而不是文件名存储对文件的引用?这样做是否会导致潜在的冲突问题? - Eric Anastas
2
如果您使用标准的加密哈希函数,您根本不需要处理碰撞问题(如果您这样做了,您已经赢得了10次彩票)。旧的MD5算法足够好,在任何地方都内置,并且是最快的算法之一。您首先确定哈希值,然后从中派生一个文件名(tohex(hashbytes) + ".dat"),并将其写入。然后您将哈希值(或文件名)存储在数据库中。完成。 - usr

0
为了解决你提到的选项1的缺点,我使用类似于fileStorage.FileExists("newfile.txt");的东西,并过滤返回负面结果的结果。
Python术语中:
import os
op = os.path

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

0

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

如果你确信需要它,那么从技术角度来看,选项1和2完全相同 - 这两个资源可能不同步,你需要定期处理以使它们一致。因此,在这里,你应该选择最适合应用程序的选项。

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

请注意,如usr所建议的使用哈希值存在理论上的冲突风险。并且你还需要像选项1和2一样进行定期处理。

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


1
数据库中存储了与文件相关的其他非二进制信息,因此我需要它。 - Eric Anastas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接