我正在开发一个在线文件管理项目。在该项目中,我们在数据库(sql server)上存储引用,在文件系统上存储文件数据;在该项目中,我们面临着文件系统和数据库之间的协调问题。上传文件以及删除文件时,我们首先在数据库中创建引用或将文件存储在文件系统上;问题是,如果先在数据库中创建引用,然后在文件系统上存储文件。 bur 在文件系统上存储文件时发生任何类型的错误。然后在数据库中创建该文件的引用,但文件系统上没有文件数据;; 请给我一些如何处理这种情况的解决方案;;我非常需要它;; 原因是什么?
这实际上比您想象的要容易一些。
首先,您需要确定“单一事实来源”。
也就是说,文件系统或数据库在任何给定时间点都是正确的,哪个是正确的?
这样做的原因是它更容易解决冲突。
您应该假设数据库是您的源,并且文件系统是数据库的影子。这似乎违反直觉,因为如果条目不在文件系统中,那么它如何存在于数据库中。显然不能。但是,基本上,如果该文件不在数据库中,那么“它不存在”。因此,文件系统反映了数据库的状态,而不是相反。
考虑到这些假设,您最终会得到这些冲突解决规则。
对于任何给定的文件:
File Exists DB Entry Exists Action
Yes Yes No action, normal state
No Yes Error -- missing file, "should never happen"
No No No action, normal state
Yes No Delete the file, but no error.
Run Code Online (Sandbox Code Playgroud)
上传文件时,存在灰色区域——即文件已上传但尚未被数据库确认时。
解决这个问题的方法是您需要以暂存模式上传文件。
执行此操作的一种简单方法是将文件上传到同一物理文件系统上的不同目录,或者使用临时文件名将其上传到最终位置。无论哪种方式,该文件都可以通过其名称或位置轻松识别为“正在处理”。
您希望将此文件“暂存”在同一文件系统上有两个原因。一、磁盘空间。如果上传时磁盘没有填满,那么您就知道它将适合其最终的安放位置(它已经“保留”了空间)。第二,当您最终放置文件时,该操作必须是原子的。同一文件系统上的文件重命名操作在现代文件系统上是原子的。基本上,您不能让文件“半重命名”,即使它不可避免地“覆盖”现有文件(原始文件在重命名操作期间被删除)。
一旦上演,您的操作将变为:
Start DB transaction
Rename file
Add DB record
Commit transaction
Run Code Online (Sandbox Code Playgroud)
如果重命名文件操作失败,您将中止并回滚数据库事务,从而回滚该条目。如果重命名成功,而数据库失败?然后就是上面列出的状态#4。重试上传直至成功。
要删除文件,请执行以下操作:
Start DB Transaction
Delete DB record
Commit transaction
Delete file from file system
Run Code Online (Sandbox Code Playgroud)
如果数据库删除失败,则不会删除该文件。如果数据库删除成功,而文件删除失败,那么我们将回到状态 #4。
最后,您有一个收割进程,它定期(每天、每周等)将数据库与文件系统进行比较,删除数据库中不存在的任何文件。由于数据库是“单一事实来源”,因此两个存储最终将保持同步。
如果包含数据库记录的文件丢失,则出现“数据损坏”。不要那样做。这是一个错误,或者有人正在遍历您的文件系统。
上传过程的重试特性和删除过程的快速失败为您提供了一个伪两阶段提交过程,可以轻松检查对错,并轻松纠正到正确的状态。