存储过程中实现业务逻辑的支持和反对观点

45

如何支持和反对将业务逻辑存储在存储过程中?


1
这个问题存在缺陷,因为它没有将面向写的业务逻辑与面向读的业务逻辑分开。我阅读了关于存储过程中逻辑支持与反对的论点,也阅读了关于CQRS和不变性等方面的文章,更多地认识到优化写操作和读操作需要不同类型的业务逻辑。你是在询问什么,是两种写和读逻辑的类别,还是只有其中一种? - Kent Bull
17个回答

37

反对存储过程:将业务逻辑放在编程空间中

我非常重视表达的能力,而且我认为SQL空间并不是很具有表现力。对于最合适的任务,请使用您手头上最好的工具。与逻辑和高阶概念摆弄最好是在最高级别上完成。因此,存储和大量数据操作最好在服务器层面上完成,可能是在存储过程中。

但这要看情况。如果您有多个应用程序与一个存储机制进行交互,并希望确保其维护完整性和工作流程,则应将所有逻辑卸载到数据库服务器中。否则,请准备管理多个应用程序的同时开发。


8
针对您关于并行开发的说法:为什么不使用应用服务器来实现业务规则,而不是将业务逻辑存储在存储过程中?使用应用服务器,所有应用程序都可以获得相同的功能,并获得去重工作的好处。这样做可以达到更好的效果。 - Tim Ferrell
不确定您所说的应用服务器是什么意思。因此,在您的模型中,没有人直接与数据库通信,而是通过某种中介应用服务器进行通信? - Mark Canlas
3
使用WCF作为例子,数据访问层将被包含在WCF服务中,该服务将根据需要转换和实现任何业务规则。UI不会直接访问任何内容,而是使用对WCF服务的服务引用,该服务将提供相应的转换结果,同时还可以让多个应用程序轻松地使用这些服务。服务将提供有关其返回内容及所需参数的元数据。 - Tim Ferrell
@MarkCanlas 当多个应用程序/服务要使用存储时,您将使用服务层。理想情况下,应用程序/服务甚至不应关心数据存储的方式或位置。持久性可以由一个微服务处理,该微服务可以通过依赖注入或服务注册表进行定位。首先看一下CQRS模式+事件溯源。 - Dasith Wijes

29

我完全反对它。其中最大的原因之一是earino所说的第一个原因——它存在于一个地方。你不能很容易地将其集成到源代码控制中。几乎不可能让两个开发人员同时在存储过程上工作。

我另一个主要抱怨是SQL不能很好地表示复杂的逻辑。你没有概念范围,代码往往被复制粘贴,因为重用代码的能力较低(与面向对象的语言相比)。

你必须给开发人员访问数据库来进行开发。在我工作过的许多组织中,数据人员和开发人员处于不同的世界,拥有不同的权限等。在这些情况下让开发人员不接触数据库会更难。


我完全同意。我无法相信开发人员继续将复杂逻辑放入存储过程中。这表明缺乏真正的领导力。 - Jeremy Ray Brown

19

我认为只要业务逻辑:

  • 在一个地方保存
  • 有适当的文档记录
  • 可以通过松散耦合的服务提供适当访问权限
  • 可以通过公开的抽象接口进行访问

我并不关心这些逻辑是存储过程、J2EE中间层、专家系统中的规则,还是其他任何地方。无论你将业务逻辑存储在哪里,“痛苦守恒定律”都会保证,总有人会说这是错误的想法,因为需要用技术/方法Y替换组件/存储库X。


业务逻辑可以位于一个处理持久性的层中,而不必成为存储过程。然而,在描述具有最终一致性模式的分布式系统时,“中心”或“一个地方”并不是正确的词语。许多微服务将具有与其自身上下文相关的业务逻辑。当描述单块系统时,“中心”或“一个地方”这个词很合适。 - Dasith Wijes
1
@DasithWijes 当我在2009年回答这个问题时,我们并没有真正关注微服务 :) - earino
我在各个公司的存储过程中看到了很多业务逻辑,但从未是最佳解决方案。在每种情况下都没有单元测试,调试更加困难。它还会将业务逻辑扩散到太多的代码源中,增加了混乱。您可以使用RESTful服务或将项目作为外部添加到其他代码源中以共享业务逻辑。迄今为止,使用存储过程的方式是我见过的最糟糕的解决方案。 - Jeremy Ray Brown

15

一些想法:请注意,这是一个以Java为中心的回答,但它是我最近(过去10年)经验的大部分

(1) 大型团队的并行开发。如果您的应用程序足够复杂,以至于每个开发人员都不能设置自己的私有版本DB(带有相关链接/参考数据等),那么很难让整个团队所有开发人员同时在共享的DEVL DB中工作于相同的PL-SQL(例如)包集?那么你就陷入了(我的经验)与在DB中使用无效的过程/代码不匹配表格的困境,因为人们进行更改...

作为一名Java架构师,我认为让每个开发人员在自己的台式机上拥有私有的JBoss实例并轻松地处理自己的功能集,以及在自己的节奏下集成而不会影响其他人... 这就是...

(2) 持续集成工具集 虽然在DB世界中存在一些类似的“概念”,但我的经验告诉我,以下组合(我在此选择我当前最喜欢的免费工具):

  • mvn-构建系统
  • junit-自动化单元测试
  • nexus-存储库管理器(管理构件的生命周期版本、快照和发布)
  • hudson-ci构建服务器
  • sonar-静态分析工具/代码覆盖率报告/更多内容

使用上述所有免费工具运行大型项目可以为众人提供一种一致/简单的方式,并对整个IT员工实施质量控制。Oracle / PL-SQL没有与之匹配的工具集

(3) 工具/库等 Java可以访问其他平台无法触及的惊人服务——有些是免费的,有些不是。甚至基本的服务,如log4j(是的,他们也有PL/SQL,但请尽量避免...这不是几乎相同的),允许开发人员创建可灵活调整的记录,可以随时更改(非常适合调试)。自动API文档(通过javadoc)。自动化单元测试覆盖率报告。令人难以置信的IDE(Eclipse)具有集成调试器/自动部署到应用程序服务器。与每种类型的服务进行接口的API,开源库可以做任何事情,并得到每个供应商的100%支持

(4) 服务重复利用。有评论说过的是对的。如果您有重度数据驱动业务规则,那么可以认为这些规则应该存在于DB层中。为什么?为了防止中间层都需要复制该逻辑。

但对于非数据驱动或足够复杂以至于OO是更自然的选择的业务规则也可以同样说。如果您将所有业务逻辑都放在DB中,则只能通过DB访问它们。

  • 如果您想要在客户端或中间应用程序层中进行验证并避免与DB交换往返时间怎么办?
  • 如果您想要在中间层缓存只读数据(以提高性能)并使业务规则针对缓存的数据执行?
  • 如果您有一个不需要DB访问的中间
    retCode = validateSomeDate(date);
    if (retCode == 1) then
       evaluateIfCustomerGetsEmail(...)//probably more stored proc invocations here...
       sendEmailMsg(....)
    else if (retCode == 2) then
       performOtherBizLogicStuf(...) //again, may need data, may not need data
       triggerExternalsystemToDoSomething(...) //may not be accessible via PL/SQL 
    fi
    

    我相信我们都见过像上面那样编写的系统,并不得不在凌晨2点调试它们。当业务逻辑分散在多个层级时,很难获得一个连贯的复杂流程的感觉,在某些情况下甚至无法维护。


11

"你不能很容易地将其集成到源代码控制中。" - 如果将创建存储过程的代码放入版本受控的脚本中,则该反对意见消失。如果您遵循Scott Ambler的敏捷数据库思想,那么这正是您应该做的。

并非所有开发人员都是优秀的数据建模者。我可以想到一些可怕的模式,这些模式是由认为略懂SQL的开发人员创建的,他们认为自己是数据库专家。我认为让开发人员与DBA和数据建模师合作具有很大的价值。

如果只有一个应用程序使用数据库,我会说业务逻辑可以出现在中间层。如果许多应用程序共享数据库,则将其放入数据库中可能更好。

SOA提供了一种中间方法:服务拥有其数据。只有服务才能访问数据;访问数据意味着通过服务进行。在这种情况下,规则可以放置在任何地方。

应用程序来来去去,但数据始终存在。


2
在源代码控制中加1。我在这里读到了许多有关源代码控制的评论。它与其他任何东西一样都是有版本控制的。 - Rob Garrison

9

不将业务逻辑存储在存储过程中的另一个原因是数据库的扩展能力有限。很常见的情况是数据库成为瓶颈,因此尽可能减轻数据库的负载是个好主意。


1
不是这样的。你可以在数据库服务器上使用虚拟化技术,并实现无限扩展。 - Uğur Gümüşhan
@UğurGümüşhan 数据虚拟化在构建基于微服务+ CQRS的现代系统时可能会变得非常复杂和缓慢(特别是变更管理)。这就是为什么几乎所有当今主要的分布式系统都是基于这些模式构建的原因。 - Dasith Wijes

6

以下是我的一些观察:

支持存储过程的优点:

  • 在项目生命周期的后期,大多数情况下瓶颈是数据库而不是Web服务器-而存储过程要快得多

  • 使用ORM生成的SQL查询进行SQL分析非常困难;而使用存储过程则非常容易

  • 您可以立即部署存储过程修复,无需服务窗口

  • 为了性能,优化存储过程比ORM代码更容易

  • 您可能有很多应用程序使用相同的数据库/存储过程

  • 任何复杂的数据场景都是存储过程的好处

支持应用程序/ORM的优点:

  • 您可以使用代码仓库(使用存储过程仍然可能,但代价高昂)

  • Java / C#语言是表达业务逻辑的更好工具

  • Java / C#更容易调试(除了动态生成的ORM SQL)

  • 独立于数据库引擎(然而这不太可能会有一个项目切换到另一个数据库引擎)

  • ORM提供易于使用的数据模型

在我看来:对于大型项目-选择存储过程,而对于其他项目-应用程序/ORM也可以很好地工作。

最终,唯一重要的是数据库。


我第一次听说存储过程的粒度时,我觉得很有意思 - 你可以立即部署一个小的修复/增强,而不必编译和部署可能包含不完整代码的较大的东西。 - Nick.McDermaid
1
应用程序越大,使用存储过程进行扩展就越困难。这就是为什么最终一致性模型和事件溯源模式非常有用的原因。 - Dasith Wijes
你的存储过程(SPs)、数据库架构、编译后的代码和配置都是一个应用程序,应该一起部署。 - Jeremy Ray Brown

6
业务逻辑应该封装在一个地方。我们可以保证逻辑始终运行并一致运行。使用涉及数据库实体的所有活动必须通过的类,我们可以确保所有验证都得到正确运行。这段代码只有一个地方,并且项目中的任何开发人员都可以轻松打开此类并查看逻辑(因为文档可能会过时,代码是唯一可靠的文档形式)。
使用存储过程很难做到这一点。您可能有多个存储过程处理相同的表格。将多个存储过程链接在一起,以便逻辑仅驻留在其中一个,这变得笨拙。这是第一次打击。如何确定“围绕实体X的所有业务规则”在数据库中?尝试跟踪数千个存储过程并找到它们真的很烦人。
第二个问题是将业务逻辑与持久性机制绑定。您可能不会将所有数据存储在同一个数据库中,或者某些数据可能存储在XML中等等。这种不一致性对开发人员来说很困难。
如果逻辑仅驻留在数据库中,则很难执行验证。您真的要调用存储过程来验证数据输入表单上的每个字段吗?验证规则和业务逻辑是亲密的表兄弟。这些逻辑应该在同一个地方执行!

5

+: SQL Server有时会优化代码

+: 您必须传递参数,这限制了SQL注入问题

-: 您的代码依赖于单个数据库(一些数据库甚至没有存储过程)

-: 要更改代码,您需要连接到数据库

-: 逻辑组织不好

个人而言,我反对使用它,但我曾经在一个非常繁忙的网站上使用过它。在MS SQL中使用存储过程带来了巨大的好处,但是一旦我实现了缓存,这些好处就不那么明显了。


4
有句话说得好:“凡是你手中拿着的都像是一枚钉子”。在我看来,并没有适用于所有情况的标准答案。很多人认为将业务逻辑放在数据库中总是错的,但我不这么认为。在数据库端进行事务处理,特别是批量操作方面,已经做了很多工作,效率非常高。此外,自从反对数据库的大多数观点形成以来,数据库中的代码管理已经极大地改进。
我认为把数据库服务器仅视为持久层是错误的。如果在DB服务器上进行处理活动最有效,则应该在那里进行。否则就在其他地方进行。这一切取决于最适合目前正在使用的应用程序、与你一起工作的团队和雇佣你的客户。以上仅供参考。

我只见过一些存储过程有用的情况(例如聚合)。但是我从来没有见过一个单独的存储过程对于业务逻辑是好的,从来没有!把它放入代码或RESTful服务中总是更好的选择,这已经100%确定了。 - Jeremy Ray Brown

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接