存储过程中针对业务逻辑的争论
在存储过程中,针对和反对业务逻辑的争论是什么?
针对存储过程:编程空间中的业务逻辑
我高度重视expression的力量,而且我没有发现SQL空间的performance力。 使用你手上最好的工具来完成最合适的任务。 摆弄逻辑和更高阶的概念最好是在最高层次上完成。 因此,存储和海量数据操作最好在服务器级完成,可能在存储过程中完成。
但这取决于。 如果有多个应用程序与一个存储机制进行交互,并且要确保它保持其完整性和工作stream程,则应将所有逻辑卸载到数据库服务器中。 或者,准备在多个应用程序中pipe理并发开发。
我完全反对。 最大的原因之一是厄尔尼诺说的第一个原因 – 它住在一个地方。 你不能很容易地把它集成到源代码控制中。 几乎不可能有两个开发人员同时在一个存储过程中工作。
我另一个主要的抱怨是,SQL在表示复杂的逻辑方面并不是很好。 你没有范围的概念,代码往往是复制粘贴的,因为重用代码的能力较差(相对于OO语言)。
你必须让开发人员访问数据库在那里开发。 在许多组织中,我曾经在数据上工作过,而不同于开发人员,拥有不同的权限等等。在这些情况下将开发人员从数据库中保存起来会更困难。
我的思想stream派说,只要业务逻辑:
- 住在一个地方
- 在哪里被正确logging
- 通过可以松散耦合的服务提供正确的访问
- 通过已发布的抽象界面
我不关心这个逻辑是否存在于一个存储过程,J2EE中间层,一个剪辑专家系统或者任何地方。 无论您在哪里存储我们的业务逻辑,“痛苦的保护法”都将保证有人会说这是错误的想法,因为组件/存储库X需要换成技术/方法Y.
一些想法:请注意,这是一个以Java为中心的响应,但它是我最近(过去10年)的大部分经验
(1)由(一个大的)开发团队同时开发。 如果你的应用程序非常复杂,每个开发者都不能build立他们自己的数据库私有版本(带有链接/参考数据等等),那么很难让所有的开发者都参与其中同一套PL-SQL(例如)包同时存储在一个共享的DEVL DB中? 然后你坚持(我的经验)与工作在一个数据库与无效的程序/表的不匹配的人作出改变…
作为一名Java架构师,我认为让每个开发人员在桌面上都拥有一个私有的JBoss实例变得更容易,并且可以轻松地在自己的一套function上进行工作,并按照自己的步调进行整合,而不会影响到其他任何人。 ..
(2)持续集成工具集虽然在DB世界中存在一些类似的“概念”,但是我的经验告诉我,(我正在挑选当前最好的同类集合):
- mvn – 构build系统
- junit – 自动化unit testing
- nexus – 回购经理(pipe理神器的生命周期版本,快照和发布)
- 哈德森 – 慈构build服务器
- 声纳 – 静态分析工具/代码覆盖率报告/更多
使用上述所有工具(免费工具)运行一个大型项目可以实现一致/简单的方式将XP交付给大众,并对整个IT人员实施质量控制。 Oracle / PL-SQL没有要匹配的工具集
(3)tools / libraries / etc … Java可以访问其他平台无法访问的一组惊人的服务 – 有些是免费的,有些则不是。 即使是基本的,如log4j(是的,他们有PL / SQL,但pulease …几乎不相同),允许开发人员创build灵活的可调整的日志logging,可以在飞行中更改(完美的dubugging) 。 自动API文档(通过javadoc)。 自动化的unit testing覆盖率报告。 具有集成debugging器/自动部署到应用服务器的令人难以置信的IDE(Eclipse)。 一个API,可以与任何types的服务进行交互,开源库可以做任何事情,每个供应商100%的支持
(4)重用服务。 什么人评论是真实的。 如果你有繁重的数据驱动业务规则,那么你可以争辩说,这些应该居住在数据库层。 为什么? 以防止中间层必须复制该逻辑。
但是对于那些不是数据驱动或者非常复杂的业务规则来说,OO是一个更自然的select 。 如果将所有业务逻辑都粘在数据库中,则只能通过数据库提供。
- 如果您想在客户端或中间应用程序层进行validation并保存到数据库的往返行程,该怎么办?
- 如果你想在中间层caching只读数据(为了性能),并且对caching的数据执行业务规则呢?
- 如果你有一个不需要数据库访问的中间层服务,或者你有一个客户端可以提供他们自己的数据呢?
- 那么,如果业务规则的数据依赖部分需要访问外部服务呢? 然后你用结构分散的业务逻辑结束,看起来像这样:
一世
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点进行debugging。 当业务逻辑在不同层级之间分散时,要想获得一个复杂stream程的连贯感,并且在某些情况下不可能维护。
“你不能很容易地把它集成到源代码pipe理中。” – 如果将创build存储过程的代码放入受版本控制的脚本中,该异议就会消失。 如果您按照Scott Ambler的敏捷数据库的想法,这正是你应该做的。
并不是所有的开发者都是好的数据build模者 我可以想到由开发人员创build的可怕的模式,他们认为对SQL的一些不熟悉的知识使他们成为数据库专家。 我认为让开发人员与数据库pipe理员和数据build模师合作有很多价值。
如果只有一个应用程序使用数据库,我会说业务逻辑可以出现在中间层。 如果很多应用程序共享数据库,那么最好把它放在数据库中。
SOA提供了一条中间道路:服务拥有自己的数据。 只有服务才能访问数据; 获取数据意味着要通过服务。 在这种情况下,可以把规则放在任何一个地方。
应用程序来来去去,但数据依然存在。
还有一个不存储业务逻辑的原因是数据库的扩展能力有限。 数据库是你的瓶颈是非常普遍的情况,这就是为什么尽可能多的加载数据库是一个好主意。
我的一些观察:
有利于存储过程:
-
在一段时间的项目生命周期之后,在大多数情况下,瓶颈是数据库而不是Web服务器 – 存储过程要快得多
-
使用sql profiler与ORM生成sql查询是非常困难的; 存储过程很简单
-
您可以立即为存储过程部署修补程序,而无需服务窗口
-
为了性能,优化存储过程比ORM代码更容易
-
你可能有许多应用程序使用相同的数据库/存储特效
-
任何复杂的数据场景都是对存储过程的投票
赞成应用程序/ ORM:
-
你可以使用代码库(存储过程仍然可能,但昂贵)
-
java / c#语言是expression业务逻辑的更好工具
-
java / c#更容易debugging(除了dynamic生成的ORM sql)
-
数据库引擎的独立性(但是,这不太可能是一个项目将数据库更改为另一个)
-
ORM提供了易于使用的数据模型
在我看来:对于大型项目 – 为存储过程,为其他人 – 应用程序/ ORM将正常工作。
在一天结束的时候,唯一重要的是数据库。
+:SQL服务器有时会优化代码
+:您被迫传递参数,这限制了SQL注入问题
– :你的代码依赖于单个数据库(有些dbs甚至没有SP)
– :要更改代码,您需要连接到数据库
– :逻辑不好组织
就我个人而言,我反对它,但我必须在一个非常繁忙的网站上使用它。 在MS SQL中使用SP带来了巨大的好处,但是一旦我实现caching,这些好处就不再那么大了。
业务逻辑应该封装在一个地方。 我们可以保证逻辑总是一直运行和运行。 使用涉及数据库实体的所有活动都必须通过的类,我们可以保证所有的validation运行正常。 这个代码有一个地方,任何项目的开发人员都可以很容易地打开这个类,看看逻辑(因为文档可以过时,代码是唯一可靠的文档forms)。
存储过程很难做到这一点。 您可能有多个处理同一个表的sproc。 将多个sprocs链接在一起,使逻辑只驻留在一个变得笨拙。 这是罢工之一。 你如何确定数据库中的“围绕实体X的所有业务规则是什么”? 玩得开心search数以千计的sprocs试图跟踪。
第二个是你将业务逻辑绑定到持久性机制。 您不能将所有的数据存储在同一个数据库中,或者某些数据可能驻留在XML中。开发人员很难对这种不一致性进行处理。
如果逻辑仅驻留在数据库中,则validation很难执行。 你真的打电话来validation数据input表单上的每个字段吗? validation规则和业务逻辑是亲密的表亲。 这个逻辑应该都在同一个地方执行!
有句俗话
当你只有一把锤子时,一切看起来都像钉子一样。
在我看来,没有一个答案能够适用于所有情况。 在我看来,很多人只是假设把商业逻辑放在数据库中总是错的。
在数据库端完成事务处理,特别是批量操作,已经做了很多工作。 而且由于大多数针对数据库的意见都已形成,数据库中的代码pipe理已经大大改善。
我认为将数据库服务器视为持久层是错误的。 如果您的处理活动在数据库服务器上完成时效率最高,请在那里执行。
如果没有,那么在别处做。
这一切都归结为最适合您目前正在使用的应用程序,与您工作的团队以及雇用您的客户。
那只是我的2美分。
在业务逻辑层中,您可以对业务逻辑进行unit testing。 如果它是完全独立的持久性操作可以被模拟,所以你只是在testingBL。 存储过程比维护/debugging/unit testing困难得多,比如linq和c#。
DBMS!=应用程序服务器
- 函数式编程(DB存储过程)与OOP。 对于大型项目来说,OOP只是标准。
- IDE – eclipse,intellij,带有所有插件的netbeans用于debugging,testing和分析只能使用真正的编程语言。 静态代码工具 。
- 版本控制,如果你得到一个PLSQL&co。 是很棒的。 如果你直接从你的IDE中获得“同步视图”,那么你是真正的幸运者。
- 扩展您的系统。 对于DB系统是地狱。 您需要为其他“节点”昂贵的硬件。 复制。 也许每个节点的许可证。 不要忘记,你仍然处于“function性编程”之中,努力理解和维护这样的系统要大得多。
- 您被困在您的数据库中,尝试更改或添加来自其他公司的新数据
- 等等…
商业逻辑的存储过程今天是不好的做法。 改用3层架构。
通过将逻辑移动到存储过程中,性能将大大提高,尤其是在涉及显式事务的情况下。
根据我的经验,应用程序开发人员不擅长编写优化的数据库代码,也不倾向于考虑并发性或性能问题。
如果将业务逻辑保存在应用程序层中,则通常需要将大量数据(通常是多次往返)转移到整个networking中,将其复制到数据库服务器的内存中,并至less一次在应用程序服务器中复制,并在您打开一个事务时在应用程序中进行逐行处理的加载。 然后,应用程序开发人员抱怨说,数据库很慢,并保持死锁。
如果你把逻辑放在数据库中的任何地方,你往往只是通过networking传递一些参数,在你等待networking资源的时候,事务不会被保留下来,整个事情就像闪电一样。 数据库当然应该像任何其他源代码一样进行源代码pipe理。有很多工具可以实现这一点。
@Nick“我完全反对,其中一个最大的原因是earino所说的第一个原因 – 它生活在一个地方,你不能很容易地把它集成到源代码控制之中,两个开发者几乎不可能存储过程在同一时间“。
并不是说我把商业逻辑放在存储过程上(相反)。 但是你提出的这些理由是没有意义的。 存储过程只是一个可以存储在源代码控制中的sql / DDL工件,也是一个部署工件(也就是说,部署交给dba进行部署,就像交付你的战争/耳朵一样工件到IT /部署stream程)一个或多个开发人员可以使用相同的存储过程closures源代码控制,就像使用普通的源代码一样 – 通过分支,版本化和合并。
现在,如果存储过程(和包含它们的包)的唯一副本只存在于数据库中,那么显然你不能用源代码控制(以及与之相关的所有问题)来控制它。 但是,这不是存储过程的问题,而是如何使用该代码的能力不足的问题。 这同样也是无能为力的performance,因为只有源代码的一个副本生产。
我曾经在拥有大量代码(包括Java和PLSQL / DDL)的系统中工作,并且都使用clearcase进行了版本pipe理。 他们都被视为源代码,将被编译和部署一个严格的过程,不同的团队在工作。 从来没有任何问题,你所描述的。
存在特定于上下文的原因,不要将业务逻辑放在存储过程中,但这些不是有效的。
高预算项目:如果您将最新的数据保存在内存中,并定期将更改保存到磁盘,则需要处理除数据库服务器之外的业务逻辑。 用例:从内存,复杂caching机制提供数据。
低预算的项目:如果您保持磁盘上的最新数据,并且您的演示文稿依赖于磁盘读取,那么在存储过程中处理业务逻辑可以节省您的开发时间。 用例:从磁盘提供数据
有不同的“商业逻辑”。 考虑根据它与其他层或服务的相关性对其进行分区。 以下是MVC视angular的一些经验法则:
a)在数据库(存储过程)中,如果它主要是数据相关的,可以用连接和相对简单的WHERE和SELECT子句来完成。
b)在控制器中是否大部分路由或调度相关; 即在屏幕或资源select方面的大规模UIstream控制。
c)在模型或视图模型中,如果涉及复杂或复杂的计算和/或条件。
d)在视图中(如Razor),如果主要是一个显示问题,比如“友好”的重新格式化并且相对容易实现。 (如果它很复杂,可以考虑把它放在视图模型中。)