由于 SQL Server 没有包,程序员如何绕过它?

Posted

技术标签:

【中文标题】由于 SQL Server 没有包,程序员如何绕过它?【英文标题】:Since SQL Server doesn't have packages, what do programmers do to get around it? 【发布时间】:2010-10-20 16:42:18 【问题描述】:

我有一个 SQL Server 数据库,其中包含大量存储过程。由于 Oracle 的“包”特性,大量存储过程在我的 Oracle 数据库中不是问题。

程序员如何解决缺少像 Oracle 那样的“包”功能?

【问题讨论】:

我个人感谢您提出这个问题。正如其他人已经清楚地注意到的那样……这是一个情绪化的话题。在 Oracle 工作 8 年后,现在在 SQL Server 工作 2 年......没有包是一个障碍。但是... SQL Server 有一些很棒的功能,比如能够在页面上编写标准 SQL 并设置变量,以及使用多连接查询更新数据的能力。甲骨文和微软只需要坐在一起...发挥他们最好的功能并创建一个漂亮的数据库系统。 【参考方案1】:

虽然 SQL Server 无法通过封装和包状态的“酷特性”像您习惯的那样提供任何东西,但您可以将存储过程组织成架构。

在企业管理器中,这些 proc 仍然全部列在一起,如果您有数百个 proc,这将形成一个巨大的树状列表。我也很怀念 Oracle 包的组织和很酷的特性。但是,所有平台都有自己的优势。

注意:用 .NET 语言编写存储过程确实可以提供封装和状态。然而,它仍然没有以任何特殊方式在 EM 树视图中将它们分开。

【讨论】:

【参考方案2】:

想出一个好的命名约定,使用它并执行它。

【讨论】:

【参考方案3】:

架构可用于组织存储过程和其他对象。就个人而言,当它们按功能区域组织对象时,我更喜欢使用模式,并且这些功能区域对应于安全边界。在 AdventureWorks 示例数据库中可以找到这方面的一个示例,该数据库具有“人力资源”和“销售”等模式。理论是给定用户可能需要访问“人力资源”中的对象,但可能不需要访问“销售”信息。

正如 James 上面所说,另一种方法是使用命名约定并强制执行它。我将补充一点,SQL Server Management Studio 有一个过滤器按钮,可用于过滤显示的对象列表。例如,可以单击“存储过程”文件夹并过滤名称包含“添加”。

在我当前的项目中,我已经将一些 SQL 查询从 SSIS 包中提取到存储过程中。为了区分这些存储过程和那些应该通用的存储过程,我在名称前加上了“ssis”。如果我可以在 C# 或 C++ 中创建类似于命名空间的东西,并创建“SSIS.SelectUserLookupData”而不是“ssis_SelectUserLookupData”,那肯定会更令人愉快。如果这些命名空间可以嵌套就更好了。

如果这是 Oracle 中 Packages 的功能之一,那么也许有人会告诉我。

【讨论】:

我喜欢您如何为您关闭为“不是问题”的问题提供答案。真正优雅。 @Jedi:我不知道如何与你共赢。一旦社区通过重新开放决定这一个问题,我就将它视为一个问题,并贡献了一些我认为以前不存在的东西。如果有人真的发现这个问题寻求帮助,我想我的回答可能会有所帮助。它来自我的经验,而不是我们讨论过的“重写”,我决定反对。 @John Saunders:所以你真的需要其他人告诉你这是一个问题?!大声笑 @Jedi:我需要其他人帮助我忽略原始问题中势利的态度,并以应该提出的方式听取问题。【参考方案4】:

我曾使用过 SQL Server 和 Oracle,因此看到了两者的优缺点。由于上述 cmets 有点热,我会尽量保持中立......

那么,什么是 Oracle 包?把它想象成一个数据库类

Package 有两个元素:头文件和正文文件。头文件是您的公共接口,包含所有可直接调用的存储过程或函数(在 Oracle 中函数返回值,存储过程不返回值)的签名(名称、参数和返回类型,如果适用)。包体必须实现包头文件中的所有过程签名。

包的主体元素包含所有实际执行工作的存储过程和逻辑。您可能在包头中声明了一个保存过程,该过程调用主体中存在的插入或更新过程。开发人员只能看到“保存”过程。重要的是要记住,包体也可以实现未在包头中声明的过程或函数,它们只是无法在包本身之外访问。

我发现软件包非常有用的原因有很多:

    您已经了解了可以提供给其他开发人员的公共接口的概念 包可以镜像你编译的类。我的 Orders.Save() C# 方法将调用我的 Oracle Orders.SaveLineItem 方法来保存每个行项目,并调用 Oracle SaveOrder 方法来保存订单摘要详细信息。 我的 proc 在包内以一种很好的、​​合乎逻辑的方式组合在一起

就我个人而言,我希望 MS 能够实现某种包功能,因为我认为它可以使数据库更加干净。

【讨论】:

我希望能够在我的“页面”上编写一个过程并使用它......而不用编译它。 Oracle 包语法允许这样做。我可以创建一个 Proc 和一个 Function 并立即使用它们而无需编译它们。 Declare - Begin - End... 声明所有变量、函数、procs...然后在 Begin - End... 中使用它们.. 全部在一个页面上。我非常希望微软让我这样做,但是唉......我必须将我的函数编译成一个包含 1000 个与我的工作无关的其他函数的列表。【参考方案5】:

未提及的包的另一个功能是“包裹”身体的能力。标头始终是公开的,任何有权执行包的人都可以查看。但这也允许他们查看正文中的代码。您可以包装主体,对其进行加密,并防止任何人看到代码实际在做什么。这是一个很好的功能,但安全性是一个大问题。

【讨论】:

【参考方案6】:

3) 反对 oracle 软件包的最佳论据是,根据 Ask Tom 网站上的经验和研究,如果不将软件包脱机,就无法更新软件包。这是无法接受的。使用 SQL Server,我们可以在不中断生产操作的情况下即时更新存储过程。

我理解这种说法的挫败感,但我不会称 id 为“不可接受”。在真实的生产环境中,永远不应该在生产环境中测试更改。更新应按计划有序地从测试环境转移到生产环境。在 24/7 系统中,冗余生产环境应在服务器更新时处理停机时间。不仅包必须脱机,而且新包如果未编译,则在重新联机时将失败。 Oracle 数据库需要一个 DBA 元素。但是,我确实想念 Oracle 软件包。

【讨论】:

按照这个答案建议的方式在 oracle 中更新包我从来没有遇到过任何问题。【参考方案7】:

看到这样一个枯燥的话题能情绪化,这有点有趣。 Oracle 有一个特性,而 SQL Server 似乎并没有对该特性的有争议的特性产生各种反应。

对于初学者来说,问题在于风格:Oracle 中的这个特性在 SQL Server 中被遗漏了,推荐的方法是什么。

无需为此情绪激动。

对于那些不喜欢 Oracle 中的打包功能的人——无论出于何种原因——他们仍然可以像使用 SQL Server 一样进行操作。

更详细地讲,样式中可能会有一个后续问题:在修改包中的函数或过程时,整个包都无效并且这“糟透了”,建议避免的方法是什么吸吮方面。

就我个人而言,我从未见过有人抱怨无法在无需重新链接的情况下修改可执行文件中的静态链接库。

【讨论】:

相信我...不要将情绪带入节省大量时间并让您以如此有意义和有用的方式组织您的“废话”突然...换工作和现在你被困在一些你认为应该留在 90 年代的东西上。我以为我只是在 Oracle 工作了 8 年时有偏见……但现在我已经在 SQL Server 工作了 2 年……Oracle 更好,是的,我对此感到很情绪化。我希望我的工作生活更轻松......而不是更难。时间就是我的生命……Oracle 为我节省了时间。【参考方案8】:

    正如人们所说,Schema 是一种组织数据库表和过程的更合乎逻辑且符合 ANSI 的方式。

    软件工程最佳实践是我们永远不应该直接在任何服务器上进行更改。由于所有数据库存储过程都是脚本化的并且在配置控制下,我们可以将这些脚本安排到我们想要的任何文件夹结构中。

(来自 AskTom 的过时信息已被删除)

【讨论】:

-1:这实际上并没有回答问题,尽管它很接近。 它确实回答了您的查询,因为它表明这是一个无效的问题。当您将架构添加到存储过程中时,它们将被组织起来。它将显示为 mypackage.my_sproc,而不是 dbo.my_sproc。其次,如果您编写数据库脚本,您将很少在数据库中查找存储过程。 "one can't update a package without making it off line" 这些关于 Oracle 包的警告声明是错误的。您可以使用 CREATE OR REPLACE 语句立即更改和编译包体。 按照这个答案建议的方式在 oracle 中更新包我从来没有遇到过任何问题。【参考方案9】:

我要感谢我的幸运星,SQL Server 没有包。 Oracle 软件包很烂。

嗯,我们需要一种方法来处理所有这些程序并将它们放在一个地方。我知道!让我们让开发人员为每个包创建和维护两个文件。他们会永远爱我们!

只要 MS 从未像 Oracle 那样实现软件包,在我看来这就是胜利。

为评论者编辑:

Oracle 包只是一种将存储过程组织成包的方法,这样您就没有 100 个存储过程,而是可能有 5 个包。它们不像 Java 或 C# 代码中的包那样可堆叠。所有软件包都处于同一级别。

一个包需要两个文件:头文件和正文文件。这在向现有包添加新过程时会产生挫败感,因为如果不添加标头就无法添加主体,即使它包含与主体中完全相同的信息。

例如,这是我的一个包的头文件中的一个 sn-p:

    PROCEDURE bulk_approve_events
(
    i_last_updated_by IN VARCHAR2,
    o_event OUT NUMBER
);

下面是正文中的相应过程:

    PROCEDURE bulk_approve_events
(
    i_last_updated_by IN VARCHAR2,
    o_event OUT NUMBER
) IS
...
BEGIN
...
END;

没有区别。头文件是无用的,只是开发人员在使用包进行开发时要跨越的另一个障碍。在我的项目中,我们有一个约定,每个过程的所有注释文档都放在标题中,以及添加时间和添加者的详细信息,但也可以很容易地包含在正文中。

【讨论】:

@Puppies:你能为我们这些不知道什么是包的人解释一下吗?如果你把情绪排除在外,那会更有帮助。如果 Oracle 软件包很糟糕,如果您以不那么情绪化的方式描述它们,它们仍然会如此。 包不需要两个文件...实际上它们不需要任何文件。 oracle 解释器可以理解 create package 语句,并且可以通过任何数据库连接发送。 为什么不同的包头和包体?因为主体可以用其他语言实现,例如 C 或 Java。此外,声明是放置公共接口的地方。不能从包的范围之外调用不在公共接口中的过程和函数。 “只要 MS 从来没有像 Oracle 那样实现包,在我看来这就是胜利。” -- 好吧,如果他们这样做了,至少你可以像在 PL/SQL 中一样定义常量,所以你不必在你的 T-SQL 代码中乱扔一千个地方的硬编码字符串值。 你错了很多。包头就像一个 IDL,(又名代理)到可用的函数、过程。 “私有”函数不会进入标题,因为它们可用于主体本身而不是外部世界。将它们分开允许以正确的顺序编译标题、正文和中间的任何内容。就像在 C、C++ 中一样,你有标题和实际的函数体(代码)。当然,更高级的语言会在幕后跟踪函数范围并为您完成繁琐的工作。在强类型中,自调用函数怎么办,因为它们不存在,所以无法编译。

以上是关于由于 SQL Server 没有包,程序员如何绕过它?的主要内容,如果未能解决你的问题,请参考以下文章

绕过安全狗进行sql注入(MySQL)

我下载了SQL server,安装了之后啥显示如快捷方式都没有,怎么回事啊,如何解决?我是win7

如何绕过Javascript中的sql注入错误

验证码绕过(on server) 和验证码绕过(on client)

如何将 SQL Server 2008 R2 SSIS 包升级到 SQL Server 2016?

由于错误 0xC001000A,无法加载包。说明:无法从 SQL Server 数据库加载指定的包