【问题标题】:How much business logic should be in the database?数据库中应该有多少业务逻辑?
【发布时间】:2009-07-26 11:56:47
【问题描述】:

我正在开发一个使用 (postgresql-) 数据库来存储其数据的多用户应用程序。我想知道我应该将多少逻辑转移到数据库中?

例如当用户要保存他刚刚输入的一些数据时。应用程序是否应该只将数据发送到数据库并由数据库决定数据是否有效?或者应用程序应该是智能部分,检查数据是否正常?

在我从事的最后一个(商业)项目中,数据库非常垃圾。没有限制,没有意见等,一切都由应用程序决定。我认为这很糟糕,因为每次在代码中访问某个表时,都会有相同的代码一遍又一遍地检查访问是否有效。

通过将逻辑转移到数据库中(带有函数、触发器和约束),我认为我们可以在应用程序中节省大量代码(以及大量潜在错误)。但是我担心将大部分业务逻辑放入数据库中会成为一个回旋镖,并且有一天它会无法维护。

是否有一些现实生活中认可的指导方针可以遵循?

【问题讨论】:

    标签: database


    【解决方案1】:

    如果您不需要大规模的分布式可扩展性(想想拥有与 Amazon 或 Facebook 等一样多的流量的公司),那么关系数据库模型可能足以满足您的性能需求。在这种情况下,使用具有主键、外键、约束和事务的关系模型可以更轻松地维护数据完整性,并减少需要完成的协调量(相信我,一旦你停止使用任何在这些事情中,您将需要和解——即使与他们合作,您也可能会因为错误而受到影响)。

    但是,大多数验证代码用 C#、Java、Python 等语言编写比用 SQL 等语言编写要容易得多,因为它们就是为这种类型而设计的。这包括验证字符串的格式、字段之间的依赖关系等。所以我倾向于在“普通”代码而不是数据库中执行此操作。

    这意味着务实的解决方案(当然也是我们使用的解决方案)是在有意义的地方编写代码。让数据库处理数据完整性,因为这是它擅长的事情,而让“正常”代码处理数据有效性,因为这是它擅长的事情。您会发现很多情况下这不成立,并且在不同的地方做事是有意义的,所以只要务实并根据具体情况权衡。

    【讨论】:

      【解决方案2】:

      两分钱:如果你选择聪明,记住不要进入“太聪明”的领域。数据库不应处理不适合其对数据的理解水平的不一致。

      示例:假设您想在一个字段中插入一个有效的(通过确认邮件检查)电子邮件地址。数据库可以检查电子邮件是否真的符合给定的正则表达式,但是要求数据库检查电子邮件地址是否有效(例如检查域是否存在、发送电子邮件和处理响应)有点太多了。

      这并不是一个真实的案例。只是为了向您说明,无论如何,智能数据库的智能性都有限制,如果不存在的电子邮件地址进入其中,则数据仍然无效,但对于数据库来说很好。就像在 OSI 模型中一样,一切都应该在其理解水平上处理数据。以太网不关心它是否正在传输 ICMP、TCP,它们是否有效。

      【讨论】:

        【解决方案3】:

        我发现您需要在前端(GUI 客户端,如果您有的话)或服务器中进行验证数据库。

        数据库可以轻松断言空值、外键约束等,即数据是正确的形状并正确链接。事务将强制对此进行原子写入。以正确的形状包含/返回数据是数据库的责任。

        服务器可以执行更复杂的验证(例如,这看起来像电子邮件吗,这看起来像邮政编码等),然后重新构造输入以插入数据库(例如,对其进行规范化并创建适当的实体插入表格)。

        您在哪里强调验证在某种程度上取决于您的应用程序。例如在 GUI 客户端中验证(比如说)邮政编码并立即提供反馈很有用,但是如果您的数据库被其他应用程序(例如批量加载地址的应用程序)使用,那么围绕数据库的层也需要验证。有时您最终会在两种不同的实现中提供验证(例如,在上面,可能是 Javascript 前端和 Java DAO 后端)。我从来没有找到一个好的战略解决方案。

        【讨论】:

          【解决方案4】:

          使用关系数据库的通用特性,如主键和外键约束、数据类型声明等是很有意义的。如果您不打算使用它们,他们为什么要使用关系数据库?

          也就是说,所有数据在进入数据库之前都应该针对类型和业务规则进行验证。类型验证只是防御性编程——假设用户想要破解你,那么你会得到更少的不愉快的惊喜。业务规则就是您的应用程序的全部内容。如果您将它们作为数据库结构的一部分,它们将与您的应用程序的工作方式更加紧密地联系在一起。如果你把它们放在应用层,那么在业务需求发生变化时更容易改变它们。

          作为次要考虑因素:与他们可用的应用程序语言相比,客户通常对他们使用的数据库(postgresql、mysql、Oracle 等)的选择更少。因此,如果您的应用程序很有可能安装在许多不同的系统上,那么最好的办法是确保您的 SQL 尽可能标准。这可能意味着构建与语言无关的数据库功能(如触发器等)将比将相同的逻辑放入应用程序层更麻烦。

          【讨论】:

            【解决方案5】:

            这取决于应用程序:)

            对于某些应用程序,哑数据库是最好的。例如,Google 的应用程序运行在一个大型的哑数据库上,该数据库甚至无法进行连接,因为需要惊人的可扩展性才能为数百万用户提供服务。

            另一方面,对于某些内部企业应用程序,使用非常智能的数据库可能是有益的,因为这些数据库通常不仅仅用于应用程序,因此您需要单点控制 - 想想员工数据库。

            也就是说,如果您的新应用程序与之前的应用程序相似,我会选择哑数据库。为了消除所有手动检查和数据库访问代码,我建议使用 ORM 库,例如用于 Java 的 Hibernate。它本质上将自动化您的数据访问层,但会将所有逻辑留给您的应用程序。

            关于验证,必须在所有级别上进行。有关详细信息,请参阅其他答案。

            【讨论】:

              【解决方案6】:

              另一个需要考虑的事项是部署。对于远程安装,我们有一个应用程序,其中数据库更改的部署实际上比实际代码库更更容易。出于这个原因,我们在存储过程和数据库函数中放置了很多应用程序代码。

              部署不是您的首要考虑因素,但它可以在决定各种选择方面发挥重要作用

              【讨论】:

                【解决方案7】:

                这既是一个人的问题,也是一个技术问题。如果您的应用程序是唯一会处理数据的应用程序(这种情况很少发生,即使您认为这是计划),并且您手头只有应用程序编码器,那么请务必保留所有逻辑应用程序。

                另一方面,如果您有可以处理它的 DBA,或者您知道需要验证多个应用的​​访问权限,那么在数据库中实际管理数据就很有意义。

                但请记住,要验证的数据库最好的事情是 a) 数据的类型和 b) 关系约束,任何自称为 RDBMS 的东西都应该处理这些约束。

                如果您的应用程序代码中有任何事务,还值得问问自己是否应该将它们作为存储过程推送到数据库,这样它们就不可能在其他地方被错误地重新实现。

                我知道有些商店只允许通过存储过程访问数据库,因此 DBA 对数据存储语义和访问限制负有全部责任,其他任何人都必须通过他们的网关。这样做有明显的优势,尤其是在多个应用程序必须访问数据的情况下。是否走那么远取决于您,但这是一种完全有效的方法。

                【讨论】:

                  【解决方案8】:

                  虽然我认为大多数数据都应该从用户界面进行验证(为什么通过网络发送已知的坏东西会占用资源?),但我也认为不对数据库施加限制是不负责任的,因为用户界面不太可能成为数据进入数据库的唯一途径。数据还来自导入、其他应用程序、在查询窗口运行的问题快速脚本修复、运行大规模更新(例如,将所有价格更新 10%)。我希望所有不良记录都被拒绝,无论它们的来源是什么,并且数据库是唯一可以保证会发生的地方。跳过数据库完整性检查,因为用户界面会这样做,这是为了保证您最终很可能会遇到数据完整性问题,然后您的所有数据都变得毫无意义和无用。

                  【讨论】:

                    【解决方案9】:

                    例如当用户要保存一些 他刚刚输入的数据。应 应用程序只需将数据发送到 数据库和数据库决定是否 数据有效吗?或者应该 应用程序是智能部分 行并检查数据是否正常?

                    最好在前端和服务器端进行验证。因此,如果数据无效,将立即通知用户。否则他将不得不等待数据库在回帖后回复。

                    当涉及安全性时,最好在两端进行验证。前端和数据库。或者数据库如何信任应用程序发送的所有数据;-)

                    【讨论】:

                      【解决方案10】:

                      验证应在客户端和服务器端完成,一旦有效,则应存储。

                      数据库应该做的唯一工作是任何查询逻辑。所以更新行、插入行、选择和其他所有事情都应该由服务器端逻辑处理,因为那是应用程序的真正核心所在。

                      正确构造插入将处理任何外键约束。让您的业务逻辑调用 sproc 将以正确的格式插入数据。我真的不考虑这种验证,但有些人可能会。

                      【讨论】:

                      • 我想知道,您是否将外键视为验证?从你的回答看不清楚。也许你可以详细说明?
                      • 我不会将 FK 视为验证表单,因为如果您构建存储过程以正确插入,那么它会很好。如果您处理 NoSQL 数据存储(Facebook、Amazon),那么您不能依赖外键。更新了我的答案
                      【解决方案11】:

                      我的决定是:永远不要在数据库中使用存储过程。存储过程不可移植。

                      【讨论】:

                      • 如何利用查询的数据库缓存。如果您的业务逻辑中有 SQL 代码,它将永远不会重用之前使用的路径,因为每个都是新查询,因为细节不同
                      • 我的经验是,中间层来来去去,但数据永远存在。 “存储过程不可移植”的说法是似是而非的,因为很少将严肃的数据从一个数据库移动到另一个数据库。抱歉,这个是我的 -1。
                      • 关于是否使用存储过程的争论并不取决于可移植性。我认为它应该基于效率之类的东西(对于数据库来说,处理大量数据比通过查询将其拉到中间层、进行计算并持久化结果更好);数据库是否由其他应用程序共享(存储的过程保持逻辑对所有人可用);接口(存储过程和视图作为向客户端隐藏架构详细信息的接口)。
                      • @Automated Tester:参数化查询的执行速度与所有流行的现代关系数据库中的存储过程相同,具有相同的缓存。这不是使用存储过程的有效参数
                      • @duffymo:在旧版软件中可以找到共享数据库。现在我们的缺点是,我想不出任何理由用共享数据库创建新软件。
                      猜你喜欢
                      • 2010-09-11
                      • 2012-03-21
                      • 2012-08-30
                      • 2011-10-23
                      • 2018-08-09
                      • 2010-10-10
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多