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

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

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

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

但不要害怕在另一个层面上重复这些逻辑来增强用户体验。

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

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

但是,当您进行报告和数据挖掘/search时,存储过程往往是更好的select。 这要归功于数据库聚合/过滤function的强大function,以及您正在处理的数据源非常接近的事实。 但是这可能不是最经典的商业逻辑。

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

将业务逻辑放在数据库中紧密地耦合到数据库的技术实现。 更改表格会导致你重新修改很多存储过程,导致大量额外的错误和额外的testing。

通常,UI取决于诸如validation之类的业务逻辑。 把这些东西放在数据库中会导致数据库和用户界面之间的紧密耦合,或者在不同情况下复制这两者之间的validation逻辑。

很难让多个应用程序在同一个数据库上工作。 一个应用程序的变化将导致其他人破坏。 这很快就会变成维修的噩梦。 所以它并没有真正的规模。

实际上,SQL不是以一种可以理解的方式实现业务逻辑的好语言。 SQL对于基于集合的操作来说是很好的,但是它没有构build“大规模编程”,很难保存大量的存储过程。 现代的OO语言更适合并且更灵活。

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

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

把它放在数据库层的一个很好的理由是:如果你确信你的客户永远不会改变他们的数据库后端。

将其放入应用程序层的一个很好的理由是:如果您的应用程序使用多个持久性技术。

你还应该考虑核心能力。 您的开发人员主要是应用程序层开发人员,还是主要是DBAtypes?

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

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

虽然没有一个正确的答案 – 这取决于有问题的项目,我会推荐Eric Evans的“ 领域驱动devise ”中提倡的方法。 在这种方法中,业务逻辑被隔离在它自己的层 – 域层 – 它位于基础结构层之上 – 可以包括你的数据库代码,在应用层之下,将请求发送到域层履行并听取确认完成,有效地推动申请。

这样一来,业务逻辑就被捕获到一个模型中,除了技术问题之外,这些模型还可以与那些了解业务的人讨论,而且应该更容易地隔离业务规则本身的变化,技术实现问题和stream程与业务(域)模型交互的应用程序。

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

在这种情况下,数据库独立性被提问者排除在外,是将逻辑从数据库中提取出来的最强有力的论据。 数据库独立性的最强有力的论据是能够将软件销售给自己偏爱数据库后端的公司。

因此,我认为将存储过程从数据库中取出的主要理由只是一个商业的,而不是技术上的。 有可能是技术上的原因,但也有技术上的原因 – 性能,完整性,并允许多个应用程序使用相同的API的能力,例如。

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

如果您使用Oracle来开发应用程序,那么PL / SQL作为一种语言是一个明显的select。 它与数据非常紧密地结合在一起,不断改进,任何体面的开发工具都将把PL / SQL开发与CVS或Subversion等结合起来。

Oracle的基于Web的Application Express开发环境甚至可以使用PL / SQL进行100%构build。

任何影响数据完整性的事情都必须放在数据库级别。 除了用户界面之外,其他的东西通常会把数据放入数据库,更新或删除数据库,包括导入数据,批量更新以改变定价scheme,修补程序等等。如果你需要确保遵守规则,那么把逻辑放在默认值和触发器。

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

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

但是,如果数据库独立性不是首要因素,而且您的团队的技能包含强大的数据库技能,那么将业务逻辑放入数据库中可能是最好的解决scheme。 您可以让您的应用程序人员执行特定于应用程序的事情,您的数据库人员可以确保所有查询都能够执行。

当然,把SQL语句放在一起并且具有“强大的数据库技能”之间有很大的区别 – 如果你的团队比前者更接近前者,那么就使用这个世界上的一个冬眠者把逻辑放在应用程序中(或改变你的团队!)。

根据我的经验,在企业环境中,您将拥有一个单一的目标数据库和这方面的技能 – 在这种情况下,您可以将所有可以在数据库中进行的操作。 如果您从事软件销售业务,则数据库许可证成本将使数据库独立性成为最大的因素,您将在应用程序层中实现您所能做的一切。

希望有所帮助。

现在可以提交到颠覆你的存储的proc代码,并用良好的工具支持来debugging这个代码。

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

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

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

将代码放在应用程序层将导致独立于数据库的应用程序。

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

它(如往常一样)取决于应用要求。

数据库中唯一存在的就是数据。

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

很难保持存储过程的良好版本控制。 数据库外的代码非常容易安装 – 当你认为你的版本错误时,你只需要做一个SVN UP(也许是安装),然后你的应用程序回到已知的状态。 您拥有环境variables,目录链接以及对应用程序的大量环境控制。

您可以使用简单的PATH操作,针对不同的情况(培训,testing,质量保证,生产,客户特定的增强等等)提供变体软件。

但是,数据库内的代码难于pipe理。 没有适当的环境 – 没有“path”,目录链接或其他环境variables – 提供任何可用的控制使用什么软件; 你有一个永久的,全局绑定在数据库中的应用程序软件,与数据结合在一起。

触发器更糟。 他们既是维护也是debugging的噩梦。 我看不出他们解决了什么问题。 他们似乎是一种围绕devise得很差的应用程序的方式,在这种应用程序中,有人不能正确地使用可用的类(或函数库)。

虽然有些人认为性能是非常有说服力的,但是我仍然没有看到足够的基准testing数据来说服我,存储过程非常快。 每个人都有一个轶事,但是没有人有algorithm差不多相同的并行代码。

[在我看到的例子中,旧的应用程序devise糟糕, 当存储过程被写入时,应用程序被重新构build。 我认为devise变更比平台变更更有影响。]

业务逻辑应该放在应用程序/中间层作为首选。 这样,它可以以域模型的formsexpression,放置在源代码pipe理中,可以与相关代码(重构)分离或组合,也可以为您提供一些数据库厂商独立性。

面向对象的语言也比存储过程更有performance力,使您能够更好,更容易地在代码中描述应该发生的事情。

在存储过程中放置​​代码的唯一好的理由是:如果这样做会产生显着和必要的性能优势,或者相同的业务代码需要由多个平台(Java,C#,PHP)执行。 即使在使用多个平台的情况下,也可以select诸如Web服务之类的方式,以更好地适应共享function。

根据我的经验,答案就在于通常由组织技能所在的位置决定的一系列价值。

DBMS是一个非常强大的野兽,这意味着正确或不恰当的处理将带来很大的好处或极大的危险。 可悲的是,在太多的组织中,编程人员主要关注; dbms技能,尤其是查询开发技巧(而不是pipe理)被忽略了。 而评估dbms技能的能力也可能被忽略,这更加剧了这一点。

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

因此,不理想的概念,如Active Records和LINQ(抛出一些明显的偏见)的普及。 但他们可能是这些组织的最佳答案。

但是,请注意,高度规模的组织倾向于更有效地使用数据存储。

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

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

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

商业应用“层”是:

1.用户界面

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

2.处理

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

3.数据库

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

什么去哪里

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

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

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

  • 可维护性
  • 可靠性

回覆。 可维护性:为了实现高效的未来发展,业务逻辑属于应用程序的一部分,最容易debugging和版本控制。

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

触发器是保持最新的一种痛苦,尤其是当你的应用程序应该在你甚至不能访问的客户端系统上运行时。 但这并不意味着不可能跟踪或更新它们。 S.洛特在他的回答中提出的这个说法是一种痛苦和麻烦是完全有效的,我会继续这样做,而且也一直在那里。 但是,如果在首次devise数据层时考虑到这些限制,并且避免将触发器和函数用于其他任何东西,但绝对必需的则是可pipe理的。

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

在我们的应用程序在现场大约一年,每天有数百个客户使用,如果我们从头开始,唯一改变的就是devise我们的系统来创build数据库function(或存储过程,不pipe你想要打电话给他们)与版本控制和更新,记住他们从头开始。

谢天谢地,我们确实有一些系统来跟踪模式版本,所以我们build立了一些系统来替代数据库function。 如果我们从一开始就考虑需要replace它们的话,那么现在就可以节省一些时间。


当然,当你走出RDBMS领域的时候,所有东西都会改变成像Amazon SimpleDB和Google BigTable这样的元组存储系统。 但这是一个不同的故事:)

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

而且我们知道它在哪里,而不必search大量的解决scheme和代码库!

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

我记得在某处读过一篇文章指出,在某种程度上,一切都可以成为商业逻辑的一部分,所以这个问题是没有意义的。

我想给出的例子是在屏幕上显示发票。 以红色标记逾期的决定是一个商业决定。

这是一个连续统一体 恕我直言,最大的因素是速度。 如何在保持良好的可维护性,性能,可扩展性,安全性,可靠性等程序devise的同时,尽可能快地使这个吸食者运行起来,并且尽可能快地运行。通常,SQL是expression某种东西的最简洁的方式,除了string操作等之外,它是性能最高的,但是这正是CLR Procs可以提供帮助的地方。 我的信念是,无论您认为最适合做什么,您都可以自由地散布业务逻辑。 如果你有一堆应用程序开发人员在查看SQL的时候扯淡了裤子,那就让他们使用他们的应用程序逻辑。 如果你真的想创build一个大数据集的高性能应用程序,尽可能多的逻辑在数据库中。 解雇您的DBA,并为开发人员提供Dev Dev数据库的最大自由。 这个工作没有答案或最好的工具。 您有多种工具,因此可以成为应用程序各个层面的专家,您很快就会发现,您花费了更多的时间来编写好的consiseexpression式SQL,并在其他情况下使用应用程序层。 对我来说,最终减less代码行数是简单的。 我们刚刚将仅有2500行应用程序代码和1000行SQL的SQL应用程序转换为现在具有15500行应用程序代码和2500行SQL的领域模型,以实现以前的SQL丰富的应用程序。 如果您可以将代码增加6倍作为“简化”,那么请继续前进。

业务逻辑通常由对象和封装,inheritance和多态的各种语言结构来体现。 例如,如果某个银行应用程序正在传递货币,则可能会有一个Moneytypes,用于定义“货币”的业务元素。 这反对用原始的小数来代表金钱。 出于这个原因,精心devise的面向对象是“商业逻辑”生活的地方,而不是任何层面。

这是一个很好的问题! 我已经提出了一个类似的问题 ,但是这个更具体。 它是由于我没有参与devise更改决定而产生的。

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

我发现这篇文章: 商业逻辑战争作者还做了一个表中的百万行参数,我觉得很有趣。 他还在JavaScript中添加了业务逻辑,这是客户端和业务逻辑层之外的部分。 我以前没有想过这个,即使我使用JavaScript进行validation多年,以及服务器端validation。

我的观点是,你希望应用程序/中间层的业务逻辑作为一个经验法则,但不要打折将数据放入数据库的情况。

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