数据库中应该包含多少业务逻辑?

9
我正在开发一个多用户应用程序,该应用程序使用(postgresql-)数据库存储其数据。我想知道我应该将多少逻辑转移到数据库中?
例如,当用户要保存他刚输入的一些数据时。应用程序只是将数据发送到数据库,然后由数据库决定数据是否有效吗?还是应用程序是智能部分,检查数据是否正确?
在我上次工作的最后一个(商业)项目中,数据库非常简单。没有限制,没有视图等,一切都由应用程序控制。我认为这很糟糕,因为每次在代码中访问某个表时,都会重复检查访问是否有效的相同代码。
通过将逻辑转移到数据库中(使用函数、触发器和约束),我认为我们可以在应用程序中节省大量代码(和潜在错误)。但我担心将太多业务逻辑放入数据库中会成为回旋镖,有一天将无法维护。
是否有一些现实生活中已经验证的指导方针可供遵循?
11个回答

13

如果您不需要大规模的分布式可扩展性(考虑像亚马逊或Facebook等公司那样的流量),那么关系型数据库模型可能已经足够满足您的性能需求。在这种情况下,使用具有主键、外键、约束和事务的关系模型可以更轻松地维护数据完整性,并减少需要进行的协调数量(相信我,一旦您停止使用其中任何一个,您将需要协调——即使使用它们,由于错误可能仍然需要协调)。

然而,大多数验证代码比如验证字符串格式、字段之间的依赖关系等,用C#、Java、Python等语言编写要比用SQL编写容易得多,因为它们是为此设计的。因此,我倾向于在“正常”的代码中执行此操作,而不是在数据库中执行。

这意味着实用的解决方案(当然也是我们使用的解决方案)是在合适的地方编写代码。让数据库处理数据完整性,因为这是它擅长的,而让“正常”的代码处理数据有效性,因为这是它擅长的。您会发现有许多情况不适用于此,因此请根据具体情况权衡利弊并采取不同的方法。


4
两个建议:如果你选择智能化,请记得不要进入“过于智能”的领域。数据库不应处理其理解程度不当的不一致性。
例如:假设您想在字段中插入一个有效的(经过确认邮件确认过的)电子邮件地址。数据库可以检查该电子邮件是否符合给定的正则表达式,但要求数据库检查该电子邮件地址是否有效(例如,检查域是否存在,发送电子邮件并处理响应)就有点过分了。
这不是一个真实的案例示例。只是为了向您说明,聪明的数据库在智能化方面有其限制,如果不存在的电子邮件地址进入其中,则数据仍然无效,但对于数据库而言可以接受。与OSI模型相似,每个组件都应在其理解程度上处理数据。以太网不关心它是否传输ICMP、TCP,也不关心它们有效性与否。

3

我发现你需要在前端(如果有GUI客户端)或服务器端以及数据库中进行验证。

数据库可以轻松地断言空值、外键约束等,即数据的形状正确且链接正确。事务将强制执行原子写入。把数据包含/返回到正确的形状是数据库的责任。

服务器可以执行更复杂的验证(例如,这是否看起来像一个电子邮件,这是否看起来像邮政编码等),然后重新构造输入以插入到数据库中(例如,归一化并创建适当的实体以插入到表中)。

在哪里强调验证在某种程度上取决于您的应用程序。例如,在GUI客户端中验证邮政编码并立即提供反馈是有用的,但如果其他应用程序使用您的数据库(例如,用于批量加载地址的应用程序),则围绕数据库的层也需要验证。有时会在两个不同的实现中提供验证(例如,在上面的示例中,可能是JavaScript前端和Java DAO后端)。我从未找到好的战略解决方案。


1

使用关系型数据库的常见特性,如主键和外键约束、数据类型声明等,是明智的选择。如果您不打算使用它们,那么为什么要使用关系型数据库呢?

话虽如此,所有数据在进入数据库之前都应该进行类型和业务规则验证。类型验证只是防御性编程——假设用户想要攻击您,那么您就会遇到更少的不愉快惊喜。业务规则是您的应用程序的核心。如果将它们作为数据库结构的一部分,则它们与应用程序的工作方式紧密绑定。如果将它们放在应用程序层中,则更容易根据业务需求进行更改。

其次,客户端通常对使用哪个数据库(postgresql、mysql、Oracle等)没有太多选择权,但可以选择可用的应用程序语言。因此,如果您的应用程序有很大可能安装在许多不同的系统上,最好确保您的SQL尽可能标准化。这可能意味着构建语言无关的数据库功能(如触发器等)比将相同的逻辑放在应用程序层中更麻烦。


1

这取决于应用程序 :)

对于某些应用程序来说,愚蠢的数据库是最好的选择。例如,谷歌的应用程序运行在一个大型愚蠢的数据库上,甚至不能进行连接操作,因为需要惊人的可扩展性才能为数百万用户提供服务。

另一方面,对于一些内部企业应用程序来说,选择非常智能的数据库可能会有益,因为这些数据库通常不仅仅用于应用程序,因此您需要一个单一的控制点 - 想想员工数据库。

话虽如此,如果您的新应用程序与以前的应用程序类似,我建议使用愚蠢的数据库。为了消除所有手动检查和数据库访问代码,我建议使用像Java的ORM库,例如Hibernate。它将基本自动化您的数据访问层,但将所有逻辑留给您的应用程序。

关于验证,必须在所有级别上进行。有关更多详细信息,请参见其他答案。


1

另一个需要考虑的问题是部署。我们有一个应用程序,在远程安装中,数据库变更的部署实际上比代码库要容易得多。因此,我们将大量应用程序代码放入存储过程和数据库函数中。

部署并不是您考虑的首要问题,但在决定各种选择方案时可能起着重要作用。


1

这不仅是技术问题,也是人员问题。如果你的应用程序是唯一一个操作数据的应用程序(即使你认为这是计划),并且你只有应用程序编码人员,那么请务必将所有逻辑保留在应用程序中。

另一方面,如果你有能够处理它的数据库管理员,或者你知道多个应用程序需要验证其访问权限,则在数据库中管理数据实际上是很有意义的。

但请记住,数据库最好验证的是a)数据类型和b)关系约束,任何自称为RDBMS的东西都应该掌握。

如果你的应用程序代码中有任何事务,请问自己是否应该将它们作为存储过程推送到数据库中,以便它们无法在其他地方被错误地重新实现。

我确实知道一些商店,只允许通过存储过程访问数据库,因此DBA对数据存储语义和访问限制负有全部责任,其他任何人都必须经过他们的网关。 这样做显然有很多优点,特别是如果多个应用程序需要访问数据。 是否采用这种方法完全取决于您,但这是一种完全有效的方法。


1

虽然我认为大多数数据应该从用户界面进行验证(为什么要发送已知的错误数据通过网络占用资源?),但我也认为不在数据库上设置约束是不负责任的,因为用户界面不太可能是数据进入数据库的唯一方式。数据还可以从导入、其他应用程序、快速脚本修复问题运行查询窗口以及运行大量更新(例如更新所有价格10%)中获取。我希望无论数据来自何处,都能拒绝所有错误记录,并且数据库是唯一可以确保这种情况发生的地方。如果跳过数据库完整性检查,因为用户界面已经完成了它,那么你最有可能最终会遇到数据完整性问题,然后你所有的数据就变得毫无意义和用处。


0
例如,当用户要保存刚输入的一些数据时。应用程序只是将数据发送到数据库,由数据库决定数据是否有效?还是应用程序是智能部分,并检查数据是否正确?
最好在前端和服务器端都进行验证。因此,如果数据无效,用户将立即收到通知。否则,他将不得不等待DB在提交后响应。
当涉及安全性时,最好在两端进行验证。前端和DB。或者,DB如何信任应用程序发送的所有数据呢?;-)

-1

应该在客户端和服务器端进行验证,一旦验证通过,则应将其存储。

数据库唯一需要做的工作是任何查询逻辑。因此,更新行、插入行、选择和其他所有操作都应由服务器端逻辑处理,因为这是应用程序的真正核心所在。

正确构造插入将处理任何外键约束。让您的业务逻辑调用一个存储过程将以正确的格式插入数据。我不认为这是验证,但有些人可能会这么认为。


你认为外键可以作为验证吗?我想知道。从你的回答中并不清楚。也许你可以详细说明一下? - Greg Beech
我不认为FK是一种验证形式,因为如果您将存储过程结构化以正确插入,则会很好。如果您处理NoSQL数据存储(Facebook,Amazon),则不能依赖外键。更新了我的答案。 - AutomatedTester

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