2010-06-24 66 views
3

我有一个基本上充当文件索引的MySQL表。每条记录的主键也是我的虚拟主机上目录中文件的名称。文件+数据库事务安全

当用户想从系统中删除一个文件,我要保证某种交易的安全性,即如果在删除记录不会被删除的文件出现错误,如果由于某种原因,数据库服务器死机该文件将不会被删除。无论发生什么事情都不太可能发生,但如果出现问题的可能性很小,我想阻止它发生。

不幸的是我绝对不知道如何实现这一点。我是否需要计算出哪些不太可能失败,并简单地假设它永远不会?有没有已知的最佳做法?

哦,这里是踢球者 - 我的虚拟主机只支持MyISAM表,所以没有MySQL交易给我。

万一它很重要,我使用PHP作为我的服务器端脚本语言。

回答

3

无论文件是通过UPDATE还是删除行从数据库中“删除”,问题都是一样的 - 数据库+文件操作不是原子操作。 UPDATE或DELETE都比另一个更安全,它们都是数据库中的事务,而文件操作不是。

解决方案是从来没有任何冲突的数据状态。只有一个来源被认为是“真相”,另一个来源则反映了这个真相。这样,如果两者之间存在矛盾,你就知道“真相”是什么。事实上,永远不会有“逻辑”的不一致性,只有磁盘上的物理文物才会表现出善后。

在大多数情况下,数据库是The Truth的更好表示。

这里的真值表:

File Exists -- DB Record exists -- Truth 
    Yes    No    File does not exist 
    Yes    Yes   File does exist 
    No    Yes   File does exist, but its in error. 
    No    No    File does not exist 

操作上,这里是如何工作的。

要创建文件,请将文件复制到最终目的地,然后在数据库中输入条目。

如果文件复制失败,则不更新数据库。 如果文件复制成功,但数据库未更新,则文件“不存在”,因此回到第一步。 如果文件复制成功并且数据库更新成功,则所有内容均为A-确定

要删除文件,首先更新数据库以显示文件被删除。 如果数据库更新成功,则删除实际的文件。 如果数据库更新没有,则不要删除该文件。 如果文件删除失败,没有问题 - 文件仍然被“删除”,因为数据库是这样说的。

如果您按照工作流程进行操作,那么在数据库表示它存在时文件应该丢失是“无法”的。如果文件丢失,您有未定义的状态,您需要解决。但是这不应该发生,除非有人在你的文件系统上行走。

数据库事务有助于保持诚实。

有时候,正如Jonathan所说,你应该运行某种清理,同步过程以确保没有任何流氓文件。但即使如此,除了文件空间,这实际上不是问题,特别是如果实际文件的文件名与原始文件名无关。 (即他们是合成文件名)这样你就不必担心覆盖等。

+0

文件名是从表中的主键生成的,专门用于防止冲突。感谢真相表 - 它让我从不同角度考虑问题总是有帮助的。 – robinjam 2010-06-24 06:38:35

+0

顺便说一下,我认为MySQL保证单个操作(如UPDATE和DELETE)的事务安全性,即它可以工作或返回错误。我错了吗? – robinjam 2010-06-24 06:43:00

+0

不,你是对的。这就是如何工作的原因,因为你总是“知道”数据库的状态(因为即使失败它也会回滚),所以它是一个更可靠的“真相源”。我只是指出更新和删除之间没有区别 - 它们作为记录文件状态的手段同样安全,而且由于数据库的事务性质,这也是如此。 – 2010-06-24 14:22:31

3

在这种情况下,我认为我会使用逻辑删除机制,即使记录仍然存在于数据库中,并且文件仍然存在于文件系统中,记录被标记为已删除。我可能会在文件被逻辑删除时将文件移动到新的位置(认为'回收站'),并使用新位置以及'逻辑删除'标记更新记录。

然后,稍后,您可以执行脱机清除操作以物理删除标记为逻辑删除的文件和记录。

这降低了实时数据的风险。它的SQL略微复杂,但鉴于可能的工作 - 重命名主表,然后创建具有相同名称的视图作为主表曾经有过,但与消除逻辑上删除的记录标准:

CREATE VIEW MainTable(...) AS 
    SELECT * FROM RenamedTable WHERE DeleteFlag = 'N'; 

即使升级到提供MySQL事务的公司并不是一个巨大的帮助。您需要一个可以在文件系统和DBMS之间运行两阶段提交协议的事务管理器,这是非常重要的。

+0

非常好的建议。我期待着在我之前进行更多的重构工作! – robinjam 2010-06-24 06:39:10

2

您可以在File表中创建具有两个值的状态列(或“is_active”列):0 =激活,1 =已删除。

  • 当用户删除文件时,只有状态字段被更改,文件保持不变。
  • 当用户浏览文件时,只显示Status = 0的文件。
  • 管理员可以查看/删除Status = 1的文件。