草庐IT

php - 文件+数据库事务安全

coder 2023-10-16 原文

我有一个基本上用作文件索引的 MySQL 表。每条记录的主键也是我的虚拟主机上目录中文件的名称。

当用户想从系统中删除文件时,我想确保某种事务安全,即如果在删除文件时出现问题,记录不会被删除,如果数据库服务器由于某种原因挂掉了文件不会被删除。发生这两种情况的可能性很小,但如果有哪怕是最微小的问题发生的可能性,我都想阻止它。

不幸的是,我完全不知道如何实现它。我是否需要弄清楚哪个不太可能失败,并简单地假设它永远不会失败?是否有任何已知的最佳实践?

哦,更重要的是——我的虚拟主机只支持 MyISAM 表,所以我没有 MySQL 事务。

以防万一,我使用 PHP 作为我的服务器端脚本语言。

最佳答案

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

解决方案是数据状态永远不会有任何冲突。只有一个来源被认为是“真相”,而另一个则反射(reflect)了那个真相。这样,如果两者之间存在不一致,您就会知道“真相”是什么。事实上,从来没有“逻辑上”的不一致,只有磁盘上物理工件所表现出来的后果。

在大多数情况下,数据库更能代表真相。

这是真值表:

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

在操作上,这是它的工作原理。

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

如果文件复制失败,则不会更新数据库。 如果文件复制成功,但数据库没有更新,则文件“不存在”,返回第一步。 如果文件复制成功,DB更新成功,那么一切都A-OK

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

如果您遵循工作流程,那么当数据库说文件存在时,“不可能”文件丢失。如果文件丢失,您将处于未定义状态,您需要解决该问题。但这不应该发生,除非有人在您的文件系统上行走。

数据库交易有助于保持诚实。

有时,正如 Jonathan 提到的,您应该运行某种清理、同步过程以确保没有任何恶意文件。但即便如此,除了文件空间之外,这真的不是问题,尤其是当实际文件的文件名与原始文件名无关时。 (即它们是合成文件名)这样您就不必担心覆盖等问题。

关于php - 文件+数据库事务安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3107552/

有关php - 文件+数据库事务安全的更多相关文章

  1. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  2. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  3. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  4. ruby-on-rails - Rails 3 中的多个路由文件 - 2

    Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

  5. ruby - 将差异补丁应用于字符串/文件 - 2

    对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

  6. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  7. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  8. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  9. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  10. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

随机推荐