41

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

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

4

24 回答 24

37

在确定业务逻辑的位置时,代码的可维护性始终是一个大问题。

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

但是,当您进行报告和数据挖掘/搜索时,存储过程通常是更好的选择。这要归功于数据库聚合/过滤功能的强大功能以及您在非常接近数据源的位置进行处理的事实。但这可能不是大多数人认为的经典业务逻辑。

于 2008-09-23T07:31:15.797 回答
31

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

但是不要担心必须在另一个级别上复制其中的一些逻辑来增强用户体验。

于 2008-09-23T07:46:03.623 回答
29

对于非常简单的情况,您可以将业务逻辑放在存储过程中。通常,即使是简单的案例也会随着时间的推移而变得复杂。以下是我没有将业务逻辑放入数据库的原因:

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

通常,UI 依赖于业务逻辑来进行验证等操作。将这些东西放在数据库中会导致数据库和 UI 之间的紧密耦合,或者在不同的情况下会重复这两者之间的验证逻辑。

让多个应用程序在同一个数据库上工作会变得很困难。一个应用程序的更改将导致其他应用程序中断。这很快就会变成维护的噩梦。所以它并没有真正扩展。

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

这并不意味着您不能使用存储的过程和视图。我认为有时在表和应用程序之间放置一层额外的存储过程和视图以将两者分离是个好主意。这样您就可以在不更改外部接口的情况下更改数据库的布局,从而允许您独立地重构数据库。

于 2008-09-23T07:40:36.227 回答
10

这真的取决于你,只要你是一致的

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

将它放在应用程序层的一个很好的理由是:如果您的应用程序针对多种持久性技术。

您还应该考虑核心能力。您的开发人员主要是应用层开发人员,还是主要是 DBA 类型?

于 2008-09-23T07:42:55.877 回答
7

虽然在应用程序层拥有业务逻辑肯定有好处,但我想指出语言/框架似乎比数据库更频繁地更改。

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

于 2008-09-23T19:08:55.247 回答
6

虽然没有一个正确的答案——这取决于所讨论的项目,但我会推荐Eric Evans在“领域驱动设计”中提倡的方法。在这种方法中,业务逻辑被隔离在它自己的层——领域层——它位于基础设施层之上——可能包括你的数据库代码,在应用层之下,它将请求发送到领域层完成并听取他们完成的确认,有效地推动应用程序。

这样,业务逻辑被捕获在一个模型中,可以与除了技术问题之外了解业务的人讨论,并且应该更容易隔离业务规则本身的更改、技术实现问题和流程与业务(领域)模型交互的应用程序。

如果你有机会,我建议你阅读上面的书,因为它很好地解释了这个纯粹的理想是如何在真实的代码和项目的现实世界中得到近似的。

于 2008-09-23T07:38:58.947 回答
6

任何影响数据完整性的东西都必须放在数据库级别。除了用户界面之外的其他事情通常会从数据库中放入、更新或删除数据,包括导入、批量更新以更改定价方案、热修复等。如果您需要确保始终遵循规则,请将逻辑置于默认值中和触发器。

这并不是说在用户界面中也有它不是一个好主意(为什么还要发送数据库不接受的信息),但是在数据库中忽略这些东西会招致灾难。

于 2008-09-23T14:12:50.417 回答
6

数据库独立性(在这种情况下被提问者排除为考虑因素)是从数据库中取出逻辑的最有力论据。支持数据库独立性的最有力论据是能够将软件出售给自己偏爱数据库后端的公司。

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

是否使用 SP 还受到您要使用的数据库的强烈影响。如果您不考虑数据库独立性,那么您将在使用 T-SQL 或使用 PL/SQL 时获得截然不同的体验。

如果您使用 Oracle 开发应用程序,那么 PL/SQL 是一种显而易见的选择。它与数据紧密耦合,在每个版本中不断改进,任何体面的开发工具都会将 PL/SQL 开发与 CVS 或 Subversion 等集成。

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

于 2008-09-23T14:32:05.927 回答
5

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

但是,如果数据库独立性不是#1 因素,并且您的团队的技能包括强大的数据库技能,那么将业务逻辑放入数据库可能是最好的解决方案。您可以让您的应用程序人员执行特定于应用程序的事情,并让您的数据库人员确保所有查询都能正常运行。

当然,能够将 SQL 语句放在一起和拥有“强大的数据库技能”之间存在很大差异 - 如果您的团队比后者更接近前者,那么使用这个世界上的 Hibernates 之一将逻辑放入应用程序中(或改变你的团队!)。

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

希望有帮助。

于 2008-09-23T08:13:37.693 回答
5

现在可以提交以颠覆您存储的 proc 代码并使用良好的工具支持来调试此代码。

如果您使用结合 sql 语句的存储过程,您可以减少应用程序和数据库之间的数据流量,减少数据库调用次数并获得巨大的性能提升。

一旦我们开始在 C# 中构建,我们就决定不使用存储过程,但现在我们正在将越来越多的代码移动到存储过程。尤其是批处理。

但是不要使用触发器,使用存储过程或更好的包。触发器确实会降低可维护性。

于 2008-12-21T19:28:42.787 回答
4

将代码放在应用程序层将产生一个独立于数据库的应用程序。

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

它(像往常一样)取决于应用程序的要求。

于 2008-09-23T07:23:20.607 回答
4

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

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

很难对存储过程保持良好的版本控制。数据库外的代码很容易安装——当你认为你有错误的版本时,你只需执行 SVN UP(可能是安装),你的应用程序就会回到已知状态。您拥有环境变量、目录链接和对应用程序的大量环境控制。

您可以通过简单的PATH操作,为不同的情况(培训、测试、质量保证、生产、客户特定的增强等)提供不同的软件

然而,数据库内的代码更难管理。没有合适的环境——没有“PATH”、目录链接或其他环境变量——来提供对正在使用的软件的任何可用控制;你有一套永久的、全球绑定的应用软件卡在数据库中,与数据结合。

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

虽然有些人发现性能论据令人信服,但我仍然没有看到足够的基准数据来让我相信存储过程是如此之快。每个人都有一个轶事,但没有人有算法或多或少相同的并行代码。

[在我看到的例子中,旧的应用程序设计得很糟糕;编写存储过程时,重新设计了应用程序。我认为设计变更比平台变更的影响更大。]

于 2008-09-23T13:03:03.517 回答
3

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

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

将代码放置在存储过程中的唯一充分理由是:如果这样做会产生显着且必要的性能优势,或者相同的业务代码需要由多个平台(Java、C#、PHP)执行。即使在使用多个平台时,也有可能更适合共享功能的替代方案,例如 Web 服务。

于 2008-09-23T07:34:52.217 回答
3

以我的经验,答案在于通常由组织技能所在的一系列价值观中的某个地方。

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

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

因此,诸如 Active Records 和 LINQ 之类的次优概念很受欢迎(以引入一些明显的偏见)。但它们可能是此类组织的最佳答案。

但是,请注意,高度扩展的组织往往会更加关注数据存储的有效使用。

于 2008-12-21T18:47:15.083 回答
2

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

于 2008-09-23T07:24:37.310 回答
2

业务逻辑将放在应用层而不是数据库中。原因是数据库存储过程始终依赖于您使用的数据库产品。这打破了三层模型的优点之一。除非您为此数据库产品提供额外的存储过程,否则您无法轻松更改为其他数据库。另一方面,有时将逻辑放入存储过程以优化性能是有意义的。

我想说的是业务逻辑要放到应用层,但也有例外(主要是性能原因)

于 2008-09-23T07:25:54.623 回答
2

业务应用程序“层”是:

1. 用户界面

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

2. 加工

这是计算和数据操作发生的地方。任何涉及更改数据的业务逻辑都在这里实现。

3. 数据库

这可能是:标准化的顺序数据库(标准的基于 SQL 的 DBMS);一个面向对象的数据库,存储包装业务数据的对象;等等

去哪儿

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

涉及数据含义和使用的业务规则大部分将在处理层中实现,但也将作为用户的工作流出现在用户界面中——以反映用户的工作。

于 2008-09-23T08:09:40.743 回答
2

恕我直言。决定业务逻辑在关系数据库驱动的应用程序中的位置有两个相互矛盾的问题:

  • 可维护性
  • 可靠性

关于。可维护性:为了实现高效的未来开发,业务逻辑属于应用程序中最容易调试和版本控制的部分。

关于。可靠性:当存在重大的不一致风险时,业务逻辑属于数据库层。关系数据库可以设计为检查数据的约束,例如不允许在特定列中使用 NULL 值等。当您的应用程序设计中出现某些数据需要处于特定状态而无法用这些简单表示的特定状态时约束,在数据库层使用触发器或类似的东西是有意义的。

触发器很难保持最新状态,尤其是当您的应用程序应该在您甚至没有访问权限的客户端系统上运行时。但这并不意味着不可能跟踪它们或更新它们。S.Lott 在他的回答中认为这是一种痛苦和麻烦的论点是完全有效的,我会支持这一点并且也去过那里。但是,如果您在首次设计数据层时牢记这些限制,并避免将触发器和函数用于除绝对必需品之外的任何事情,那么它是可以管理的。

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

在我们的应用程序在该领域使用了大约一年之后,每天有数百名客户使用,如果我们要从头开始,我唯一会改变的就是设计我们的系统来创建数据库函数(或存储过程,但是你想给他们打电话)从一开始就考虑到他们的版本控制和更新。

值得庆幸的是,我们确实有一些系统来跟踪模式版本,所以我们在此基础上构建了一些东西来处理替换数据库函数。如果我们从一开始就考虑更换它们的必要性,它现在会为我们节省一些时间。


当然,当您走出 RDBMS 的领域,进入像 Amazon SimpleDB 和 Google 的 BigTable 这样的元组存储系统时,一切都会发生变化。但这是一个不同的故事:)

于 2008-12-21T17:57:30.583 回答
1

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

我们知道它在哪里,而无需搜索大量的解决方案和代码库!

于 2008-09-23T07:27:51.467 回答
1

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

于 2008-09-23T07:37:32.317 回答
1

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

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

于 2008-09-23T07:56:27.390 回答
1

这是一个连续体。恕我直言,最大的因素是速度。您如何才能让这个傻瓜尽快启动并运行,同时仍然坚持良好的编程租户,例如可维护性、性能、可伸缩性、安全性、可靠性等。SQL 通常是表达某些东西的最简洁的方式,而且恰好是性能最高的很多次,除了字符串操作等,但这就是您的 CLR Procs 可以提供帮助的地方。我的信念是在任何你认为最适合手头工作的地方自由地散布业务逻辑。如果您有一群应用程序开发人员在查看 SQL 时大吃一惊,那么让他们使用他们的应用程序逻辑。如果您真的想创建一个具有大型数据集的高性能应用程序,请将尽可能多的逻辑放入数据库中。解雇你的 DBA' s 并为开发人员提供对其开发数据库的最大自由。这项工作没有唯一的答案或最佳工具。您拥有多种工具,因此成为应用程序各个级别的专家,您很快就会发现您花费了更多时间编写良好的简洁表达 SQL,并在其他时间使用应用程序层。对我来说,最终,减少代码行数是导致简单性的原因。我们刚刚将一个只有 2500 行应用代码和 1000 行 SQL 的富 sql 应用程序转换为现在具有 15500 行应用程序代码和 2500 行 SQL 的域模型,以实现以前的富 sql 应用程序所做的事情。如果您可以证明代码增加 6 倍是“简化的”,那么请继续。您拥有多种工具,因此成为应用程序各个级别的专家,您很快就会发现您花费了更多时间编写良好的简洁表达 SQL,并在其他时间使用应用程序层。对我来说,最终,减少代码行数是导致简单性的原因。我们刚刚将一个只有 2500 行应用代码和 1000 行 SQL 的富 sql 应用程序转换为现在具有 15500 行应用程序代码和 2500 行 SQL 的域模型,以实现以前的富 sql 应用程序所做的事情。如果您可以证明代码增加 6 倍是“简化的”,那么请继续。您拥有多种工具,因此成为应用程序各个级别的专家,您很快就会发现您花费了更多时间编写良好的简洁表达 SQL,并在其他时间使用应用程序层。对我来说,最终,减少代码行数是导致简单性的原因。我们刚刚将一个只有 2500 行应用代码和 1000 行 SQL 的富 sql 应用程序转换为现在具有 15500 行应用程序代码和 2500 行 SQL 的域模型,以实现以前的富 sql 应用程序所做的事情。如果您可以证明代码增加 6 倍是“简化的”,那么请继续。最终,减少代码行数是导致简单性的原因。我们刚刚将一个只有 2500 行应用代码和 1000 行 SQL 的富 sql 应用程序转换为现在具有 15500 行应用程序代码和 2500 行 SQL 的域模型,以实现以前的富 sql 应用程序所做的事情。如果您可以证明代码增加 6 倍是“简化的”,那么请继续。最终,减少代码行数是导致简单性的原因。我们刚刚将一个只有 2500 行应用代码和 1000 行 SQL 的富 sql 应用程序转换为现在具有 15500 行应用程序代码和 2500 行 SQL 的域模型,以实现以前的富 sql 应用程序所做的事情。如果您可以证明代码增加 6 倍是“简化的”,那么请继续。

于 2011-08-05T19:33:37.213 回答
1

这是一个很好的问题!在我已经问过一个类似的问题后,我发现了这一点,但这更具体。它是我没有参与制定的设计变更决定的结果。

基本上,我被告知的是,如果您的数据库表中有数百万行数据,那么请考虑将业务逻辑放入存储过程和触发器中。这就是我们现在正在做的事情,将 Java 应用程序转换为存储过程以实现可维护性,因为 Java 代码变得复杂。

我在以下网站上找到了这篇文章:The Business Logic Wars 作者还在一个表参数中创建了百万行,我觉得这很有趣。他还在 javascript 中添加了业务逻辑,这是客户端和业务逻辑层之外的。尽管我多年来一直使用 javascript 进行验证,以及服务器端验证,但我之前没有考虑过这一点。

我的观点是,您希望将应用程序/中间层中的业务逻辑作为经验法则,但不要忽视将其放入数据库中有意义的情况。

最后一点,我目前正在工作的另一个小组正在为研究做大量的数据库工作,他们处理的数据量是巨大的。尽管如此,对他们来说,他们在数据库本身中没有任何业务逻辑,而是将其保留在应用程序/中间层中。对于他们的设计,应用程序/中间层是它的正确位置,所以我不会将表的大小作为唯一的设计考虑因素。

于 2013-08-14T17:43:50.120 回答
0

业务逻辑通常由对象以及封装、继承和多态的各种语言结构来体现。例如,如果银行应用程序正在传递金钱,则可能有一个 Money 类型,它定义了“金钱”是什么的业务元素。这与使用原始小数来表示货币相反。出于这个原因,精心设计的 OOP 是“业务逻辑”所在的地方——而不是严格意义上的任何层。

于 2008-09-23T07:57:30.397 回答