编程中的典型错误操作(第一部分)

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"摘要"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"软件开发是一项越来越普遍的工作,但是在开发的过程中,有一些错误是我们经常遇到,或者是一犯再犯的,所以George在本文中整理了在服务器和操作系统级别以及数据库级别常见的错误。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文是该系列的第一篇。第二篇已发布"},{"type":"link","attrs":{"href":"https:\/\/www.infoq.cn\/article\/A4C1vGKDOlcI69MqBvlL","title":"xxx","type":null},"content":[{"type":"text","text":"编程中的典型错误操作(第二部分)"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"italic"}],"text":"本文最初发表于"},{"type":"link","attrs":{"href":"https:\/\/primalskill.blog\/mistakes-were-made-part-1","title":null,"type":null},"content":[{"type":"text","marks":[{"type":"italic"}],"text":"Primal Skill Programming网站"}],"marks":[{"type":"italic"}]},{"type":"text","marks":[{"type":"italic"}],"text":",经原作者George授权,由InfoQ中文站翻译分享。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"编程中的错误是有害的,这一点大家都没有异议吧?不管怎样,我们都应该竭力避免它们,否则的话,就会导致我们花费额外的金钱、错失最后期限,并且会引发焦虑,不仅对你来讲会这样,对你的客户同样如此。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在我17年的编程生涯中,我依然记得我犯过的最大错误是不小心删除了客户的生产数据库。真要命!当时估计的损失会有几十万美元,但是后来幸运的是,我“找到了”几天前的手动备份,所以最终没有想象中的那么糟糕。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"开发人员可能会犯无数的错误,开发人员的生活便是如此,但是有些类型的错误你应该尽力避免。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我通过两篇系列文章的方式将这些错误分门别类地列出来,因为毕竟千禧一代的年轻人都喜欢列表(每"},{"type":"text","marks":[{"type":"italic"}],"text":"个都在快速扫视,没有人再去详细阅读任何东西,好了,吐槽结束"},{"type":"text","text":")。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"服务器和操作系统级别的错误"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这可能不完全是开发人员的权限,而是DevOps或系统管理员团队的权限,不过,我经常看到在小型的开发公司中,开发人员具有访问服务器的权限,这其实也没什么,不是每个公司都有成立专门部门的预算,但是需要确保你不要犯下面的错误。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"自己托管一切"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"虽然在世界某个地方的数据中心中托管自己的专用服务器是一件很好的事情,而且这种方式也更能节省成本,但是前提是你要知道要做哪些事情。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"大多数的专用服务器都是非托管的,这意味着你可以租用数据中心的物理服务器,但配置相关的事情都要自己来做。数据中心提供了最低限度的安全性,这里的安全性只涉及到数据中心的其他服务器,但在操作系统层面却没有做太多的事情。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"为了实现这种安全性和最佳配置,你需要一个受管理的专用服务器,在这里还需要雇佣一个专门的系统管理团队,但是这些服务器要花很多的钱。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"问一下自己,你是否真的需要一个专门的服务器?如果你只想要托管一个简单的网站,可能是一个WordPress博客,那么我们有大量的可选方案:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/wpengine.com\/","title":null,"type":null},"content":[{"type":"text","text":"WPEngine"}]},{"type":"text","text":"用来托管WordPress"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"http:\/\/dreamhost.com\/","title":null,"type":null},"content":[{"type":"text","text":"DreamHost"}]},{"type":"text","text":"用来实现简单的网站托管"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"或者从数以百万计的供应商中选择VPS服务器托管"}]}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"没有备份"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果你能够从本文或者一般的编程经验中学到什么的话,那就是:"},{"type":"text","marks":[{"type":"italic"},{"type":"strong"}],"text":"创建那些该死的备份"},{"type":"text","text":",不仅仅是项目的备份,还有个人数据的备份。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"很多的初学者甚至资深的程序员都会犯这样错误,那就是不创建备份,不使用版本控制,不备份数据库。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"你可以使用不同的备份策略,但需要知道一件重要的事情,那就是在同一台服务器上进行备份是不行的。如果服务器被黑客攻击了或者以某种方式遭到了破坏该怎么办?你所有的备份也将付诸东流。备份始终应该被转移到另外一台单独的服务器上。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"你应该知道有两种备份类型,即"},{"type":"text","marks":[{"type":"strong"}],"text":"逻辑备份和物理备份"},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"逻辑备份是从数据库中提取实际的数据,并将它们以文本或二进制的形式存储到文件中。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"物理备份将整个的数据库信息提取到一个文件中,包括数据库和表元数据、写前日志(write-ahead log,WAL),以及完整恢复数据库所需的所有必要信息。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以,哪种方式更重要呢?逻辑备份更容易实现,对于小型的数据库来说,这确实是我们所需的方式,而物理备份的方式实现起来更为复杂,如果你的项目规模正在变大的话,那么你可能在某个时间点会用到这种方式。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"不正确的日志设置"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以日志的方式记录服务器、数据库和应用的数据,"},{"type":"text","marks":[{"type":"strong"}],"text":"并确保对它们进行分析"},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"很多的开发人员要么在服务器上实现日志(通过在操作系统上预先定义),要么在应用层面实现日志。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"好的日志策略可以为你省去大量的麻烦和开发时间,更不用说它还能帮助我们预防可能的黑客攻击。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"只有当你不断监控应用、数据库和服务器上发生了什么的情况下,日志才有意义。从最基本的层面来讲,你所需要的只是错误日志,随后你可以实现进程日志,以及可选的调试日志。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"你可以实现各种各样的策略,从简单的文件日志开始,到去中心化的日志管理器和聚合器,比如"},{"type":"link","attrs":{"href":"https:\/\/www.elastic.co\/logstash","title":null,"type":null},"content":[{"type":"text","text":"Logstash"}]},{"type":"text","text":"或"},{"type":"link","attrs":{"href":"https:\/\/kafka.apache.org\/","title":null,"type":null},"content":[{"type":"text","text":"Kafka"}]},{"type":"text","text":"。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"没有缓存"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们都知道这样一个说法,"},{"type":"link","attrs":{"href":"https:\/\/martinfowler.com\/bliki\/TwoHardThings.html","title":null,"type":null},"content":[{"type":"text","text":"计算机科学领域有两个难题"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在现代Web应用开发中,缓存是非常重要的。不是每个人都有千兆的互联网连接,实际上,世界上很多人都在使用3G的连接速度浏览互联网。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"缓存可以为你的项目提供极大的帮助,而实施一个成功的缓存策略则取决于你的实际背景。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"你可以了解的技术包括:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"如果你使用WordPress的话,可以了解"},{"type":"link","attrs":{"href":"https:\/\/wordpress.org\/plugins\/w3-total-cache\/","title":null,"type":null},"content":[{"type":"text","text":"W3 Total Cache"}]},{"type":"text","text":"。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"对于通用的PHP来说,OpCode cache可以提供帮助。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"更细粒度的缓存解决方案是"},{"type":"link","attrs":{"href":"https:\/\/varnish-cache.org\/intro\/index.html#intro","title":null,"type":null},"content":[{"type":"text","text":"Varnish Cache"}]},{"type":"text","text":"。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"对于数据库缓存来讲,"},{"type":"link","attrs":{"href":"https:\/\/redis.io\/","title":null,"type":null},"content":[{"type":"text","text":"Redis"}]},{"type":"text","text":"或"},{"type":"link","attrs":{"href":"https:\/\/memcached.org\/","title":null,"type":null},"content":[{"type":"text","text":"Memcached"}]},{"type":"text","text":"是不错的解决方案(注意,这两项技术并不仅仅局限于数据库缓存)。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":5,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/www.cloudflare.com\/learning\/cdn\/what-is-a-cdn\/","title":null,"type":null},"content":[{"type":"text","text":"内容交付网络(CDN)"}]},{"type":"text","text":"也能为我们提供帮助。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"缺少维护"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"你应该实施的一个良好策略就是定期的维护周期,在每个周期里,你需要更新服务器、数据库、应用依赖等等。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"代码会不断变得陈旧,会出现缺陷,就像其他的产品一样,代码也有一个生命周期,在周期结束后它会重构、更新或删除。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在旧的代码上运行项目会带来很多的麻烦,这样你的代码、服务器和数据库都更易于受到攻击。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以我来看,如果是中小型的项目,应该每周对服务器和数据实施一次维护周期,并且要对你的实际代码及其依赖实施两周一次的维护周期。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"数据库级别的错误"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"为所有的开发环境使用同一个数据库"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"对于任何项目来说,混合使用数据都不是一个好的长期解决方案。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一个经过“实战检验”的解决方案就是为每个开发环境使用不同的数据库,主要包括:开发、staging和生产。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"随着像Docker这样的容器化软件的诞生,在开发环境中启用一个新的隔离容器,复制生产服务器和数据库的配置是一件非常容易的事情。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"不进行性能审计"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"当一个网站运行缓慢的时候,如果不是网络问题的话,那大多数就是数据库的问题。数据库是Web应用的第一个瓶颈。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不对数据库进行定期的性能审计是很多开发人员所犯的一个错误,这是因为他们在本地开发环境中没有看到性能的下降。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们可以做的第一个性能方面的修复就是检查在要进行查询的表的列中,是否添加了恰当的索引(比如,当你使用SQL的时候,出现在WHERE语句中的列)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"关于数据库性能的文章可以单独写一整个系列,所以我不会在这里展开论述,但你应该查看"},{"type":"link","attrs":{"href":"https:\/\/use-the-index-luke.com\/","title":null,"type":null},"content":[{"type":"text","text":"Use the index, Luke!"}]},{"type":"text","text":"网站以了解更多细节,而且可以购买作者编写的“"},{"type":"link","attrs":{"href":"https:\/\/amzn.to\/3rJotf5","title":null,"type":null},"content":[{"type":"text","text":"SQL Performance Explained: Everything developers need to know about SQL performance"}]},{"type":"text","text":"”,这是一本对数据库和性能进行深入研究的书。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"不进行安全审计"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最常见的数据库黑客攻击类型是SQL查询注入攻击。每个开发者都应该知道并关心在他们的Web应用程序上可能被攻击的手段。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"当你在你的项目中加入越来越多的工具和技术时,这不仅增加了复杂性,而且增加了黑客可能进行的攻击类型,从而能使你的Web应用面临一系列的潜在攻击。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"幸运的是,有大量关于这个主题的教程,请阅读以下资源:"}]},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/owasp.org\/www-community\/attacks\/SQL_Injection","title":null,"type":null},"content":[{"type":"text","text":"OWASP的SQL注入文档"}]}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/SQL_Injection_Prevention_Cheat_Sheet.html","title":null,"type":null},"content":[{"type":"text","text":"SQL注入预防手册"}]}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"http:\/\/sqlmap.org\/","title":null,"type":null},"content":[{"type":"text","text":"SQLMap渗透测试工具"}]}]}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"忽视数据完整性"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在数据库中操纵数据时,如果操作不当,很容易对数据造成破坏。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这是我多年来看到的,开发人员在操作数据时犯的最大错误。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果你要插入、更新或删除相关数据的话,要始终使用事务来实现。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"例如,我们有一个葡萄酒目录的数据库,将葡萄酒本身的数据保存在一个表中,将针对该葡萄酒的订单保存在另一个表中。如果由于某种原因,有种酒停产了并且从数据库中删除了,但订单却没有被删除,当我们试图查看订单或者对其进行分析时,将导致数据被破坏,因为所有的订单将指向数据库中已经不存在的葡萄酒条目。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有人认为,当删除某种葡萄酒的时候,也可以执行删除相关订单的操作,但如果分开进行的话(例如,两个单独的DELETE查询,一个接着一个去执行),倘若出现数据库连接丢失或其他原因,仍然可能导致数据损坏。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在这种情况下,最好使用事务,这样可以保证"},{"type":"text","marks":[{"type":"italic"}],"text":"在事务内"},{"type":"text","text":"执行的查询总是一起执行的,如果其中一个查询失败,事务也会失败,并且变更会回滚到原来的状态。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"不关心敏感数据"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"“纯文本”?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"让我感到惊讶的是,即使是在今天,将敏感数据存储在纯文本中仍然是一个问题,这样的错误开发人员还在犯。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"即使是大的开发公司也会犯这样的错误,用纯文本存储密码、用纯文本泄露敏感信息的日志等等,这样的例子数不胜数。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"密码应该始终"},{"type":"text","marks":[{"type":"strong"}],"text":"以散列形式存储"},{"type":"text","text":"。好的散列算法是"},{"type":"link","attrs":{"href":"https:\/\/en.wikipedia.org\/wiki\/Blowfish_(cipher","title":null,"type":null},"content":[{"type":"text","text":"Blowfish"}]},{"type":"text","text":"或"},{"type":"link","attrs":{"href":"https:\/\/en.wikipedia.org\/wiki\/Twofish","title":null,"type":null},"content":[{"type":"text","text":"Twofish"}]},{"type":"text","text":",大多数数据库引擎都原生支持它们。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"开发者犯的另一个大错是他们没有使用经过实战检验的加密算法,相反,他们试图采用自己的加密算法。"},{"type":"text","marks":[{"type":"strong"}],"text":"不要试图重新发明轮子"},{"type":"text","text":"。我有个坏消息要告诉你,这么做将会失败,非常糟糕。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"加密算法是由数学家而不是Web开发人员创造的。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"结论"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"软件开发非常有趣,并且是令人兴奋的,但要把它作对却是很难的。80\/20法则告诉我们,最后的20%决定了一个Web应用的成败,并占用了80%的开发时间。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我希望你喜欢这篇文章,请继续关注第二部分,我将会讨论在应用层面可能发生的错误。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"欢迎评论并分享这篇文章,如果你有任何问题,可以在"},{"type":"link","attrs":{"href":"https:\/\/twitter.com\/feketegy","title":null,"type":null},"content":[{"type":"text","text":"Twitter"}]},{"type":"text","text":"上联系我。"}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章