我一直在阅读Dan Chak的"Enterprise Rails"一书,它让我想到:你觉得你应该在数据库级别和应用程序级别都有数据限制吗?或者你觉得类似于Ruby on Rails这样的自以为是的框架 - 数据库只是数据的"哑存储库",所有检查都应该在你的应用程序中完成(我不是想在这里挑出RoR - 我是一个我自己的Rails的巨大粉丝,但我不同意它对数据库的方法)?
就个人而言,我觉得你应该同时拥有它们,以确保你的数据库和应用程序安全.我的意思是你应该使用非空约束,如果已知的话给你的字段一个长度(而不是将它们全部留在nvarchar(255)),在数据库上有诸如外键,检查约束和触发器之类的东西,然后还通过应用程序中的业务逻辑规则强制执行此操作.IMO通过其用户界面使您的应用程序更加健壮,并且还可以防止可能直接访问数据库的人员.
我经常看到的反驳论点是它需要重复逻辑; 一次在数据库级别,一次在应用程序级别 - 假设您有一个检查约束来验证是否输入了产品的SKU(即它的长度大于零).
您现在还需要在业务逻辑中包含验证方法,以确保用户输入的值的长度大于零,并且可能还有一些客户端Javascript用于在用户键入数据时捕获错误.
我认为这不是一件坏事 - 是的,你有一些重复的逻辑,但最终结果是"数据库作为堡垒"的思维模式,因为如果你考虑它,你的数据是你应用程序中最重要的部分; 毕竟,如果数据容易被破坏和泄露,那么你的新Web 2.0应用程序有什么用?
你对此有何看法?数据库应该是像诺克斯堡这样难以穿透的堡垒,还是一个被激光守护的开放式保险箱?换句话说,您是否应该牺牲一些逻辑重复来确保安全的数据模型,或者将所有内容留给您的应用程序并使用数据库来存储数据?
简而言之:数据库应该强制执行约束.
为什么:
更轻松.对于前者 要在特定数据列上设置约束,只有一个地方可以设置它:列本身.数据可能来自各种来源,但检查是放在最终数据处理的地方.
诚信.数据库应负责其托管的数据.不一致的数据库与没有数据库一样好.
灵活性.新的UI开发环境经常出现.如果数据库提出要说它会处理约束,那么前端开发和功能测试就更容易了.
是的,如果您想限制数据库中的内容.这些层应尽可能彼此不同,并且您的数据库不应依赖于另一层,以确保它遵循规则.
无法保证错误(或恶意)"业务逻辑"层不会将有毒数据插入到您的表中.当然,如果你可以相信其他层,你可能不需要它.但我在大型机商店工作,在那里DBA总是要解决由年轻的Java whippersnappers将他们的错误代码推广到生产而没有充分(任何?)测试的问题:-).
在不同开发区域之间共享的数据库表(以及它们对我们来说都是共享的)应始终保护自己免受错误数据的影响.当App A将狡猾的数据放入App B使用的表中时,不是App A开发人员就会受到攻击,而是DBA.
如果您关注数据库的Jeff Atwood学校只是一个愚蠢的数据存储和检索系统,那么您可以将所有验证放在应用程序层中.
但是,我发现应用程序就像小孩子一样.如果不加以控制,他们会扔掉房间里的一切.父母要清理这些烂摊子.在这种情况下,DBA将进行清理.
但是,我认为您需要小心使用每个数据库数据完整性功能,因为它就在那里.使用外键约束和触发器重载数据库可能会产生比您想象的更多问题.我倾向于只在非常密切相关的表上使用外键,例如标题/详细信息表对.如果您开始在任何地方添加外键,您最终可能会得到一个无法管理的数据库.
我很少使用触发器.我认为他们使数据库非常不透明.您发出一个简单的更新/插入/删除命令,可能会发生奇怪的事情.我猜有两个触发器不可避免的地方:
如果您没有为应用程序写入数据库的源代码,则需要修改该行为.触发器是您唯一的选择.
如果要对视图执行CRUD操作.对于插入/更新/删除操作,触发器是必需的.
我倾向于在应用程序中执行基本验证.通过这种方式,用户可以立即得到错误的反馈.需要查找相关表的复杂验证最好在数据库中完成(以及应用程序执行的简单验证).我认为,在不使用复杂的锁定策略的情况下,在应用程序级别几乎无法保证某些形式的验证.
如果您有多个应用程序,可能在不同平台上使用不同语言编写,则可以加强将更多验证放入数据库层的情况.由不同程序员编写的两个或多个应用程序执行相同验证的可能性相当低.最好在一个地方做.
这个世界的杰夫阿特伍德建议您编写一个所有应用程序用来与之通信的Web服务.Web服务执行数据验证.这样做可以使数据库保持一个愚蠢的存储容器,从而使您可以切换数据库引擎.实际上,您很少更改数据库引擎(除非您从Microsoft Access开始!).如果您正在编写Web服务纯粹是为了集中数据验证,那么我觉得你太过分了.
如果您确定永远不会有其他客户端应用程序,那么您可能会将数据库视为一个简单的存储.但是,如果您将拥有多个客户端应用程序,显然您将不得不在所有客户端应用程序中复制约束,这是一个坏主意.请记住,其他客户包括开发人员工具
此外,通过将数据库用作"哑库",您很可能最终会得到效率较低的应用程序.数据库可以比应用程序更有效地完成许多工作.为什么不利用这个呢?
我认为您应该不惜一切代价保护您的数据.没有什么比尝试报告具有错误数据的应用程序更糟糕的了,因为应用程序有错误.现在这是什么意思?
您应该通过FK强制执行您的关系,没有理由不这样做.您应该尝试避免空值,并且仅在空值适当时使用它们.我确实认为有一条细线.
你应该解析一个电话号码,以确保它的格式正确吗?可能不是,但是你应该再次将电话号码存储在没有格式化问题的模式中.
通常总会有一些重复,而数据库不仅仅是愚蠢的存储库.
数据库确保数据级别的完整性.外键约束,非空约束和大小约束都基本上由数据库涵盖.
你不能在数据库中做所有事情,但你可以做很多事情.保护数据.
提升一个级别,您就拥有了业务逻辑.通常,这是您与其他应用程序(Web服务,您自己的UI等)集成的关键点.这里将业务逻辑编码到应用程序中.如果产品的结束日期为x,那么如果y具有不同的结束日期,那么它也不会出现在y中.
在数据库中描述这种规则很难,所以你不这样做.但是,您的业务逻辑层仍会拦截它知道无效的事物.例如,如果不允许描述字段为空,则业务逻辑不应将其发送到数据库.无论如何都会出错,但你试图在他们被认为是坏的时候拦截事物.
在数据库中也很难表达其他"规则",例如"如果新用户来自Arkensas,则有1年的有效期,否则为2年,除非他们有3个孩子,其中一个被命名为Barry".我们可以嘲笑这个例子,但经验丰富的程序员会告诉你,业务逻辑是最大的矛盾之一.
移动到UI,UI还定期在屏幕中编码业务逻辑.表单和其他页面通常会以无效状态存在,并且UI的工作是至少在大多数时间知道规则.希望UI将逻辑推迟到业务层,但业务层不知道字段1是截止日期,字段2是描述.
如果用户已经选择了小部件Y,则UI知道用X搜索产品.UI知道需要描述,并且项目计数大于0且小于100(在这些示例中,良好的UI将依赖于业务层到告诉它,例如,min和max,但UI仍然知道这种关系)
在Web UI中,我们还添加了客户端脚本,它再次复制了服务器代码中的逻辑.我们使用客户端脚本来获得更好的用户体验,但最终不要相信来自客户端的任何内容(可以关闭脚本,手动操作表单字段等)
所以你可以看到逻辑将被复制.你试图尽可能地减少重复,但实际上很少有可能给出一个非常重要的程序.