数据库中的业务逻辑与代码中的区别?

77
作为一名软件工程师,我倾向于在应用层编写业务逻辑,而通常只在数据库中依靠CRUD(创建、检索、更新和删除)操作。另一方面,我遇到过一些应用程序(通常是较旧的应用程序),其中大量的业务逻辑是写在存储过程中的,因此有些人更喜欢在数据库层编写业务逻辑。
对于那些已经或喜欢在存储过程中编写业务逻辑的人来说,使用这种方法的原因是什么呢?

15
我是一名数据库管理员。数据逻辑应该在数据库中处理。为了完成所需的功能,你操纵数据库结构的方式应该被保留在数据库中。 当你将这些操作组合成更大的一系列流程(业务逻辑)时,这些流程可以被合并到应用程序中。 - Guy
IT经理是问题所在。他们误用DBA,期望他们成为系统开发的一部分。DBA只是使用手头的工具。我是一个全栈开发者。我已经清理了多年的“数据逻辑”,并说服我的雇主禁止使用存储过程来处理业务流程,在从数百个查询中提取Excel电子表格工作之后,其中一个过滤了财务数据。处理只属于应用程序,其中界面为用户提供控制和信息。换句话说,SP仅用于数据库工作,而不是用户数据输入。 - RBJ
16个回答

49

我尽量在数据库中严格限制业务逻辑,仅使用必须进行大量查询和更新才能执行单个应用程序操作的存储过程。有些人可能会争辩甚至这些也应该在应用程序中处理,但如果可以减少IO操作,我更愿意将其留在数据库中。

数据库非常适合进行CRUD操作,但是如果它们被繁琐的逻辑所充斥:

  1. 逻辑会变得混乱不清,
  2. 通常情况下,数据库作为一个孤立的单元,无法像应用服务器一样进行横向扩展。
  3. t_sql/PLsql很难阅读,而且具有过程化的性质。
  4. 你将放弃所有面向对象分析和设计的好处。

4
T-SQL和其他SQL变种可能难以阅读,但我认为它们是声明式的而不是过程式的--游标是其中一个例外。 - Scott Lawrence
2
那么你如何处理事务呢?例如:假设我需要在我的系统中创建一个新订单。在这种情况下,业务场景要求系统:记录订单、向客户发送电子邮件(向emailQueue表添加一行),并且(这是棘手的部分)如果order.type=1 -> 更新table1,否则更新table2。所有这些都必须在单个事务中完成。您会在业务逻辑层中编写此代码并处理事务,还是将所有内容移动到数据库中? - Uri Abramson
17
"t_sql/PLsql很难阅读" - 基于什么?它只是代码。我可能认为Objective-C很难读,但另一个人可能认为它是自面包以来最直观的语言。这是否意味着Objective-C很难读?并不是。语言只是一种工具,只是语法。你可以编写糟糕的PL/SQL代码,就像你可以编写糟糕的C#代码一样。但在任何情况下,这都不是语言的错,而是编写代码的人的错。一个语言是否“难以阅读”主要取决于你对它的熟悉程度。 - dcp
3
我不一定同意这个答案。你如何定义逻辑?它只是一堆计算和推导吗?还是包括其中交织的过程?应用程序仅仅是一个呈现层,那些有着复杂应用端逻辑的“胖客户端”已经过时了。此外,从应用程序调用单个批量操作可能在逻辑或数据库查询/插入/更新/删除期间遇到严重的性能问题,而调整数据库端要比调整应用程序端逻辑更加容易和高效。 - Anjan Biswas
1
此外,应用程序越来越向异步处理方向发展,其中用户在UI中执行操作A并继续进行操作B,但操作A仍在后台异步运行,而不会让用户等待其完成。这种异步行为的高效实现几乎不可能仅通过在应用程序级别编写完整的业务逻辑来实现。 - Anjan Biswas
显示剩余4条评论

38
尽可能将业务逻辑保留在最易于测试和调试的环境中。虽然其他人的答案中存储业务逻辑有一些有效的理由,但它们几乎总是被这个原则所压倒。请注意,这里的环境指的是编程环境,而不是物理环境。

没错。我也曾经开发过非常复杂的应用程序和嵌套式数据库,其中超过一半的业务逻辑都在数据库中。如果我想把条件和逻辑放在类或库中,那将是一场噩梦,并且会让最终用户几乎拥有所有权限。其他方面,如身份验证、ACL、比较等也是如此。 - Fury
3
这个问题最简洁的回答奖项颁给了... - Jason Glover
2
让我们来看看测试和调试可能只占与数据库查询的生命周期相关时间的1%的1%,所以是的,要为此进行优化。这是多么愚蠢的观念。也许只有当你一直在数据库中工作时,你才不会觉得调试和测试那么困难。我当然不觉得困难。仅仅因为某样东西与你所习惯的不同,并不意味着你不能使用它,如果它是最适合工作的最好工具的话。 - HLGEM
2
“也许,如果你一直在数据库中工作……”听起来像是你承认你只有一个工具,而且它是一把锤子。也许,在构建逻辑复杂的系统时,有些人更喜欢确保行为正确性而不是执行速度。“我不知道它是否正确,但它很快!” - user74754

22

仅将业务逻辑限制在应用层中,最多只是短视的。有经验的专业数据库设计人员很少允许其存在于系统中。数据库需要拥有约束、触发器和存储过程来帮助定义任何来源的数据如何进入其中。

如果要保持数据库的完整性并确保所有新数据或数据更改的来源都遵循规则,则必须将所需逻辑放置在数据库中。将其放在应用程序层中会导致数据问题的出现。数据库不仅从一个应用程序获得信息。应用程序中的业务逻辑通常会在导入时被意外忽略(假设您有一个新客户想要将其旧历史数据导入到您的系统中,或者一大批目标记录,没有人会通过界面输入数百万个可能的目标。它将在导入中处理),也会被通过查询窗口进行的更改而绕过以解决一次性问题(例如将所有产品价格增加10%的事情)。如果您有应该应用于数据更改的应用程序层逻辑,但没有应用该逻辑,那么它就无效了。现在将其放在应用程序层中也可以,没有必要将错误数据发送到数据库并浪费网络带宽,但不在数据库中添加此逻辑迟早会导致数据问题。

将所有这些内容保留在数据库中的另一个原因与用户可能会犯欺诈有关。如果您将所有逻辑都放在应用程序层中,那么您必须直接向表授权用户访问权限。如果您将所有逻辑封装在存储过程中,则可以限制它们仅执行存储过程允许的操作,而不做其他任何事情。我不会考虑允许用户以任何方式访问存储财务记录或个人信息(如健康记录)的数据库,就像我不会允许除几个数据库管理员之外的任何人直接访问生产记录一样。比许多开发人员意识到的更多的欺诈行为已经发生了,几乎没有人在他们的设计中考虑这种可能性。

如果需要导入大量数据,则通过数据访问层进行导入可能会减慢其速度,因为它未利用数据库旨在处理的基于集合的操作。


31
是的,数据可以来自多个应用程序,但这并不意味着您必须将逻辑放在数据库中。在数据库上方有另一层,所有应用程序都必须通过该层。这就是n层系统架构背后的原因。如果您想导入大量数据,为什么要假定直接将其导入数据库?可以使用服务层开发批量导入应用程序,然后通过相同的业务逻辑层传输数据。 - Andy McCluggage
12
我能说的是,你从未花费数月时间修复像那样糟糕的设计所导致的错误数据。我有过这样的经历。数据库并不仅仅用于数据持久化。 - HLGEM
12
恰当构建的多层设计并非本质上有问题。像大多数人一样,你显然遇到过一些设计不佳的情况。我也曾经历过这种情况,但从来没有让我认为将所有业务逻辑放在数据库中是一个好主意。事实上,我见过的最混乱、最难以理解的情况就是这样做的。 - Andy McCluggage
9
@HLGEM - 我非常喜欢您的回答。我完全同意业务规则需要储存在数据库中。关于安迪所提到的编写“中间层”的观点,如果该中间层语言过时了怎么办?例如,如果中间层8年前是用VB6编写的,现在你要怎么做才能将其转换成更易于维护的语言?需要全部重写吗?如果您将业务规则放在数据库中,它们就会一直在那里,并且可以轻松地维护多年。20年前没有人使用Java,但很多人都在使用Oracle。 - dcp
7
如果你的数据库变得过时怎么办?这和你反对过时的中间层语言的论点是一样的...尽管数据库语言的寿命比许多编程语言要长,但仅仅因为你不想改变任何东西而坚持某种语言只会使你错失多年来产生的所有创新。我对数据库业务逻辑的主要抱怨是它几乎从来都不是DRY的,所以一次更改将需要您检查所有内容以确保其正常工作... - Populus
显示剩余7条评论

17

您对“业务逻辑”这个术语的使用比较模糊。

它可以被解释为包括对数据的约束执行(也称为“业务规则”)。对于这些的强制执行绝对应该在dbms中进行。

它也可以被解释为包括诸如“如果有新客户到来,那么在一周内我们会给他发送欢迎信。”之类的内容。试图将这种东西推入数据层可能是一个巨大的错误。在这种情况下,“创建新的欢迎信”的驱动程序应该是触发新客户行插入的应用程序。想象一下,每次新的数据库行插入都会触发一封新的欢迎信,然后突然我们接管了另一家公司并必须将该公司的客户集成到我们自己的数据库中……哎呀。


2
这个答案具有最深入的见解。 - Pacerier
是的,我认为这个问题可以从不同的层面来回答。我完全同意数据约束应该由模式来强制实施。 - wobbily_col

14

我们在数据库层面上进行很多处理,如果适当的话。有很多操作不适合将大型数据集拉回应用程序层面进行分析。这对我们来说也更容易部署 —— 一个单一的点 vs. 在所有安装点更新应用程序。但很多取决于你的应用程序及其所做的事情;这里没有单一的好答案。


7
如果“业务逻辑”指的是应用程序流程、用户控制、定时操作以及通常的“业务处理”,那么它应该在应用层中。但如果它的意思是确保无论你如何挖掘数据,它总是有意义且是一个合理的、非自相矛盾的整体,那么强制执行这些规则的检查就应该放在数据库中,绝对没有问题。总有很多方法将数据推入数据库并在其到达后进行操作。并非所有这些方法都内置了“业务逻辑”。例如,在支持电话呼叫的DOS窗口中进行的SQL会话非常自由!如果逻辑不在数据库中以确保所有数据更改都是有意义的,那么可以肯定地说,数据随着时间的推移会变得非常混乱。而且,由于系统只有它所持有的数据有价值,因此这会导致投资回报率大大降低。

7

有时我会在存储过程中加入“逻辑”,因为CRUD可能会发生在多个地方。所谓的“逻辑”并不是真正的业务逻辑,而是更多的“完整性逻辑”。它可能是相同的 - 如果以某种方式删除或更新某些内容,并且如果该删除或更新可以从具有不同代码库的多个工具中进行,则需要进行一些清理,将其放入所有工具都使用的存储过程中是有意义的。

此外,有时“业务逻辑线”非常模糊。以报告为例 - 它们可能依赖于封装了关于架构对业务意义的“智能”的存储过程或视图。您是否见过基于列值或其他标准“执行操作”的CASE语句等?这可能被解释为业务逻辑,但它确实属于可以进行优化等的数据库中。


好观点...我过去实际上也做过类似的事情。 - senfo

7

将业务逻辑放在数据库中的两个好处是:

  • 它可以保护您的逻辑和数据,防止其他应用程序访问数据库时没有实现类似的逻辑。
  • 数据库设计通常比应用层更持久,这样在客户端移动到新技术时可以减少工作量。

3
如果您在数据库中有某种数据完整性或其他业务逻辑,您是否完全将其排除在“业务逻辑”层之外?还是要进行复制?(例如,在输入到数据库之前检查值是否有效,即使数据库本身不允许输入?) - Edan Maor
38
数据库是用于数据持久性的。如果您按照您的建议进行操作,那么您就是在为失败而构建。需要相同数据的其他应用程序应该受到控制,而不是由数据级别本身来控制。如果不这样做,却说“哦,数据库会控制这个”,那么你将自己暴露于巨大的疏忽之中。此外,数据库设计比应用程序存在时间更长,因为它们太难改变。这也是为什么您要尽可能少地将其放入其中的原因。您将逻辑与数据捆绑在一起的越多,随着事物发生变化,您就要付出越多的工作量去解决。 - Ty.
3
在某些情况下,复制逻辑可以是有意义的,因为它可以通过减少与后端的网络往返次数来提高性能。但您仍然需要在后端拥有安全保障。 - dpbradley
8
@Ty - 我们可能都可以举出支持我们观点的经验例子,但是当你涉及到具有数百个表和高事务处理率的足够复杂的应用程序,并且这些应用程序由需要共享数据的几十个应用程序访问时,我会选择在后端使用逻辑。 - dpbradley
2
@Jack - 能否解释一下?如果你有不同的观点,请发表自己的答案回答这个问题。 - dpbradley
显示剩余2条评论

5

通常情况下,在数据库层中可以找到业务逻辑,因为在进行更改和部署时,这样做通常会更快。我认为,通常不是出于将逻辑放置在那里的最好意图,而是由于部署的便利性而导致它最终被放在那里。


部署是否更容易比实现单元测试更重要? - fabpico

4
我在一家金融公司工作,州政府规定了某些规则,这些规则和它们的计算几乎每天都会变化,如果不是每周必然变化。鉴于这种情况,将处理计算逻辑的部分移动到数据库中更有意义;可以在不重新编译和重新分发应用程序的情况下测试和应用更改,否则每天进行这样的操作会干扰业务,这是不可能的。存储过程经过测试、批准、应用后,最终用户对此毫不知情。
随着向基于Web的应用程序的转移,将逻辑移动到数据库的依赖性减少了,但仍然存在。即使是Web应用程序(取决于语言),也必须编译并发布到网站上,这可能会导致停机时间。

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