业务逻辑:数据库或者应用程序层

时间:2020-03-06 14:35:02  来源:igfitidea点击:

古老的问题。我们应该将业务逻辑放在哪里,作为存储过程(或者程序包)放在数据库中,还是放在应用程序/中间层中?更重要的是,为什么?

假设数据库独立性不是目标。

解决方案

将代码放在应用程序层中将生成一个独立于DB的应用程序。

有时出于性能原因,最好使用存储过程。

它(通常)取决于应用程序要求。

这个问题没有独立的正确答案。这取决于应用程序要求,开发人员的偏好和技能以及月亮的阶段。

业务逻辑将放置在应用程序层而不是数据库中。
原因是数据库存储过程始终取决于我们使用的数据库产品。这打破了三层模型的优势之一。除非我们为此数据库产品提供额外的存储过程,否则我们不能轻易地切换到其他数据库。
另一方面,有时候将逻辑放入存储过程中以优化性能是有意义的。

我要说的是将业务逻辑放入应用程序层,但是有例外(主要是性能原因)

我们在存储过程中放置​​了很多业务逻辑,这不是很理想,但是通常它是性能和可靠性之间的良好平衡。

而且我们知道它在哪里,而不必搜索大量解决方案和代码库!

确定业务逻辑应该去哪里时,代码的可维护性始终是一个大问题。

集成的调试工具和更强大的IDE通常使中间层代码的维护比存储过程中的相同代码更容易。除非确实有其他原因,否则我们应该从中间层/应用程序而不是存储过程中的业务逻辑开始。

但是,当我们进行报告和数据挖掘/搜索时,存储过程通常是更好的选择。这要归功于数据库聚合/过滤功能的强大功能以及我们一直在密切处理数据源的事实。但是,无论如何,这可能不是大多数人认为的经典业务逻辑。

作为首选,应将业务逻辑放在应用程序/中间层中。这样,它可以以域模型的形式表示,放置在源代码管理中,可以与相关代码分离或者组合(重构)等。它还为我们提供了一些数据库供应商独立性。

面向对象的语言也比存储过程更具表现力,使我们可以更好,更轻松地在代码中描述应该发生的事情。

将代码放置在存储过程中的唯一好理由是:这样做会产生重大而必要的性能优势,或者同一业务代码需要由多个平台(Java,C#,PHP)执行。即使在使用多个平台时,也存在诸如Web服务之类的替代方案,它们可能更适合于共享功能。

可伸缩性也是在中间层或者应用程序层而非数据库层中使用业务逻辑的非常重要的因素。应该理解,DatabaseLayer仅用于与数据库进行交互,而不处理返回数据库或者从数据库返回的操作。

虽然没有一个正确的答案取决于所讨论的项目,但我还是建议使用Eric Evans在"域驱动设计"中倡导的方法。在这种方法中,业务逻辑在其自己的层中隔离,即域层位于基础结构层(可能包含数据库代码)之上,而在应用程序层之下,后者将请求发送到域层以实现和侦听其完成的确认,从而有效地驱动应用程序。

这样,可以将业务逻辑捕获到一个模型中,该模型可以与除技术问题之外的了解业务的人员进行讨论,并且应该可以更轻松地隔离业务规则本身,技术实施问题和流程中的更改与业务(域)模型交互的应用程序。

如果有机会的话,我建议我们阅读上述书籍,因为它很好地解释了在实际的代码和项目的真实世界中如何真正地近似于这种纯粹的理想。

对于非常简单的情况,我们可以将业务逻辑放入存储过程中。通常,即使简单的案例也随着时间的流逝而变得复杂。这是我不将业务逻辑放入数据库中的原因:

将业务逻辑放入数据库中,会将其与数据库的技术实现紧密耦合。更改表将导致我们再次更改许多存储过程,从而导致大量额外的错误和额外的测试。

通常,UI依赖于业务逻辑来进行诸如验证之类的事情。将这些内容放入数据库中将导致数据库和UI之间的紧密耦合,或者在不同情况下会在两者之间重复验证逻辑。

在同一个数据库上运行多个应用程序将变得很困难。一种变化的变化将导致其他断裂。这会很快变成维护噩梦。因此,它并没有真正扩展。

实际上,SQL并不是一种以易于理解的方式实现业务逻辑的好语言。 SQL非常适合基于集合的操作,但是它错过了"大规模编程"的构造,因此很难维护大量的存储过程。现代的OO语言更适合于此,并且更加灵活。

这并不意味着我们不能使用存储的proc和视图。我认为有时在表和应用程序之间增加存储过程和视图的额外层以使两者分离是一个好主意。这样,我们可以更改数据库的布局而无需更改外部接口,从而可以独立地重构数据库。

只要我们保持一致,这完全取决于我们。

将其放入数据库层的一个很好的理由:如果我们相当确定客户永远不会更改其数据库后端。

将其放置在应用程序层中的一个很好的理由:如果我们要为应用程序定位多种持久性技术。

我们还应该考虑核心竞争力。开发人员主要是应用程序层开发人员,还是主要是DBA类型的开发人员?

在数据库中放置足够的业务逻辑,以确保数据一致和正确。

但是不必担心必须在另一个级别上复制某些逻辑以增强用户体验。

我记得在某处读过一篇文章,该文章指出,在某种程度上,一切都可以很好地成为业务逻辑的一部分,因此这个问题毫无意义。

我认为给出的示例是在屏幕上显示发票。将过期的标记为红色的决定是一项商业决定。

业务逻辑通常由对象以及封装,继承和多态性的各种语言构造体现。例如,如果银行应用程序正在传递金钱,则可能存在定义"金钱"的业务元素的金钱类型。这与使用原始小数表示货币相反。因此,精心设计的OOP并不是严格地存在于任何层中的"业务逻辑"。

业务应用程序的"层"是:

1.用户界面

这实现了业务用户对h(is / er)作业的看法。它使用用户熟悉的术语。

2.加工

这是计算和数据处理发生的地方。此处涉及涉及更改数据的任何业务逻辑。

3.数据库

这可能是:规范化的顺序数据库(基于标准SQL的DBMS); OO数据库,存储包装业务数据的对象;等等。

什么去哪里

在进入以上各层时,我们需要进行必要的分析和设计。这将指示最佳实施业务逻辑的位置:有关数据更新的数据完整性规则和并发性/实时性问题通常应与计算的字段尽可能地接近数据,这是一个很好的指针到存储过程/触发器,其中绝对需要数据完整性和事务控制。

涉及数据含义和使用的业务规则大部分将在处理层中实现,但也将出现在用户界面中,因为用户的工作流以某种顺序链接了各个过程,从而反映了用户工作。

如果需要数据库独立性,我们可能需要将所有业务逻辑放在应用程序层中,因为应用程序层中可用的标准比数据库层中可用的标准更为普遍。

但是,如果数据库独立性不是第一位因素,并且团队的技能水平包括强大的数据库技能,那么将业务逻辑放入数据库中可能被证明是最佳的解决方案。我们可以让应用程序人员执行特定于应用程序的事情,而数据库人员则可以确保所有查询都能进行。

当然,如果团队比前者更接近前者,然后使用这个世界的休眠者之一将逻辑放入应用程序中,则可以将一条SQL语句放在一起和拥有"强大的数据库技能"之间存在很大的区别(或者更改团队!)。

以我的经验,在企业环境中,我们将拥有一个目标数据库,在此情况下,我们将在此领域中拥有的所有技能都可以放入数据库中。如果我们从事软件销售业务,那么数据库许可成本将使数据库独立性成为最大因素,并且我们将在应用程序层中实现所有可能的实现。

希望能有所帮助。

进入数据库的唯一内容是数据。

存储过程是维护的噩梦。它们不是数据,也不属于数据库。开发人员与DBA之间无休止的协调无非是组织上的摩擦。

很难对存储过程保持良好的版本控制。数据库外部的代码非常容易安装-当我们认为版本错误时,只需执行SVN UP(可能是安装),然后应用程序就会返回已知状态。我们具有环境变量,目录链接以及对应用程序的许多环境控制。

通过简单的" PATH"操作,我们可以拥有适用于不同情况(培训,测试,QA,生产,客户特定的增强功能等)的变体软件。

但是,数据库内部的代码很难管理。没有适当的环境-没有" PATH",目录链接或者其他环境变量-无法提供对所使用软件的任何可用控制。我们在数据库中拥有永久的,全局绑定的应用程序软件集,与数据结合在一起。

触发条件甚至更糟。它们既是维护工作,又是调试工作的噩梦。我看不出他们解决了什么问题;它们似乎是解决设计不良的应用程序的一种方法,在这些应用程序中,人们不必费心地正确使用可用的类(或者函数库)。

尽管有些人觉得性能论点引人注目,但我仍然没有看到足够的基准数据来说服我存储过程是如此之快。每个人都有一个轶事,但是没有一个人的并排代码算法大致相同。

[在我所看到的示例中,旧的应用程序设计得很烂。编写存储过程时,将重新构造应用程序。我认为设计变更的影响要大于平台变更的影响。]

任何影响数据完整性的内容都必须放在数据库级别。除了用户界面之外,其他操作通常会将数据放入数据库,从数据库中更新数据或者从数据库中删除数据,包括导入,批量更新以更改定价方案,修补程序等。如果需要确保始终遵循规则,请将逻辑设置为默认和触发器。

这并不是说在用户界面中也拥有它不是一个好主意(为什么要麻烦发送数据库不会接受的信息),而是忽略数据库中的这些内容是为了讨好他们。

在这种情况下,发问者将数据库独立性作为考虑因素,这是从数据库中提取逻辑的最有力依据。关于数据库独立性的最有力论据是能够将软件出售给对数据库后端有自己偏好的公司。

因此,我认为将存储过程从数据库中取出的主要论据仅仅是商业上的,而不是技术上的。可能出于技术原因,但是将其保留在其中也有技术原因,例如性能,完整性以及允许多个应用程序使用同一API的能力。

是否使用SP也会受到将要使用的数据库的强烈影响。如果我们不考虑数据库独立性,那么使用T-SQL或者使用PL / SQL将会有非常不同的体验。

如果我们使用Oracle开发应用程序,那么PL / SQL作为一种语言显然是一种选择。它与数据紧密耦合,在每次发布中都不断得到改进,并且任何不错的开发工具都将PL / SQL开发与CVS或者Subversion等集成在一起。

甲骨文基于Web的Application Express开发环境甚至是使用PL / SQL 100%构建的。

虽然在应用程序层上具有业务逻辑当然有好处,但我想指出的是,语言/框架似乎比数据库更频繁地进行更改。

在过去的10到15年中,我支持的某些系统通过了以下UI:Oracle Forms / Visual Basic / Perl CGI / ASP / Java Servlet。一件事并没有改变关系数据库和存储过程。

恕我直言。确定业务逻辑在关系数据库驱动的应用程序中的位置时,存在两个相互冲突的问题:

  • 可维护性
  • 可靠性

回覆。可维护性:?为了进行有效的将来开发,业务逻辑属于应用程序中最容易调试和版本控制的部分。

回覆。可靠性:当存在很大的不一致风险时,业务逻辑属于数据库层。关系数据库可以设计为检查数据约束,例如不允许在特定列等中使用NULL值吗?当应用程序设计中出现一种情况,即某些数据需要处于特定状态,而这些状态过于复杂而无法用这些简单的约束来表达时,则可以使用触发器或者其他某种方式在数据库层中类似。

触发器是保持最新状态的痛苦,尤其是当应用程序应该在没有访问权限的客户端系统上运行时。但这并不意味着不可能跟踪或者更新它们。 S.Lott在回答中说这是痛苦和麻烦的论点是完全正确的,我将第二次提到这一点,并且也曾去过那里。但是,如果我们在初次设计数据层时牢记这些限制,并且除了绝对必要之外,不要将触发器和函数用于任何其他事情,但它是可管理的。

在我们的应用程序中,大多数业务逻辑包含在应用程序的模型层中,例如发票知道如何根据给定的销售订单进行初始化。当针对一系列复杂的更改依次修改一堆不同的东西时,我们将它们汇总在事务中以保持一致性,而不是选择存储过程。总计等的计算均使用模型层中的方法完成。但是,当我们需要对某些东西进行非规范化以提高性能或者将数据插入所有客户端使用的"更改"表中以找出它们需要在会话缓存中过期的对象时,我们在数据库层使用触发器/函数来插入新并从此触发器发出通知(Postgres监听/通知内容)。

在我们的应用程序在现场使用了大约一年之后,每天都有成百上千的客户使用它,如果要从头开始,我唯一要更改的就是设计用于创建数据库功能(或者存储过程)的系统想要打电话给他们),并从一开始就考虑到版本控制和更新。

值得庆幸的是,我们确实有一些系统可以跟踪模式版本,因此我们在此之上构建了一些东西来替换数据库功能。但是,如果我们考虑从一开始就需要替换它们,那么现在可以为我们节省一些时间。

当然,当我们走出RDBMS领域进入诸如Amazon SimpleDB和Google的BigTable之类的元组存储系统时,一切都会改变。但这是一个不同的故事:)

根据我的经验,答案在于通常由组织技能所在的价值观所决定的范围之内。

DBMS是一种非常强大的野兽,这意味着正确或者不正确的处理将带来巨大的利益或者巨大的危险。可悲的是,在太多的组织中,主要关注的是编程人员。 dbms技能,尤其是查询开发技能(相对于管理技能)被忽略。评估dbms技能的能力也可能缺失的事实使情况更加恶化。

很少有程序员充分了解他们对数据库不了解的内容。

因此,次优概念的流行,例如Active Records和LINQ(造成一些明显的偏差)。但是它们可能是此类组织的最佳答案。

但是,请注意,规模较大的组织倾向于更加关注数据存储的有效使用。

如今,可以通过良好的工具支持将存储的proc代码提交颠覆并对其进行调试。

如果我们使用结合了sql语句的存储的proc,则可以减少应用程序和数据库之间的数据通信量,并减少数据库调用的次数,并获得较大的性能提升。

一旦开始在Cwe中进行构建,我们就决定不使用存储的proc,但是现在我们将越来越多的代码移至存储的proc。特别是批处理。

但是,请勿使用触发器,使用存储的proc或者更好的程序包。触发器确实会降低可维护性。