存储过程是数据库中的一种特殊类型的SQL程序,它封装了一系列SQL语句和逻辑,可以被远程程序、另一个存储过程或命令行调用。存储过程通常被称为SPROCS或SPs。存储过程的特性和命令语法是特定于数据库引擎的。传统上,Oracle使用PL/SQL作为其语言,而SQL Server使用T-SQL。
存储过程可以被看作有三个主要部分:
存储过程可以接受参数值作为输入。根据参数的定义,可以修改值并将其传回调用程序。
存储过程可以执行SQL语句,使用条件逻辑(如IF THEN或CASE语句)和循环结构来执行任务。存储过程能够调用另一个存储过程。存储过程可以通过游标操作SQL查询的结果,游标允许过程逐行访问结果。本质上,可以使用游标遍历SQL语句的结果。这可能会降低数据库性能,因此请明智地使用游标!
存储过程可以返回单个值,如数字或文本值,或结果集(一组行)。如前所述,根据输入的定义,可以向调用过程传播更改的值。
以下是一个接受参数、执行查询并返回结果的存储过程示例。具体来说,存储过程接受BusinessEntityID作为参数,并使用此参数与HumanResources.Employee表的主键匹配以返回请求的员工。虽然此示例返回单行,但由于匹配主键,存储过程也可以用来返回多行或单个(标量)值。
CREATE PROCEDURE uspFindEmployee
@BusinessEntityID INT
AS
BEGIN
SELECT *
FROM HumanResources.Employee
WHERE BusinessEntityID = @BusinessEntityID
END
要从此SQL Server命令行或另一个存储过程调用此存储过程,将使用以下命令:
EXEC HumanResources.uspFindEmployee 3
存储过程也可以从编程语言中调用。每种语言,如PHP或C#,都有其特定方法来实现这一点。
使用存储过程有几个优点。虽然将每个查询都封装在存储过程中并不明智,但使用它们有一些很好的理由。以下是一些经常提到的优点:
存储过程可以包含许多命令并处理大量信息以获得所需的结果。通过将所有编程逻辑保留在服务器上,可以避免将查询结果通过网络传输到客户端程序进行处理。
数据库可以处理许多客户端和调用程序。但数据库处理来自自定义程序(如C#)和内置程序(如Excel)的请求并不少见。为了确保关键业务逻辑保持一致,将业务逻辑在存储过程中运行而不是依赖每个版本的程序来实现和正确执行规则是有意义的。
这有助于保持一致性,因为程序执行相同的逻辑。这也意味着数据质量更好。
当复杂的业务规则和编程逻辑被集中到存储过程中时,进行更改变得更加容易。不需要在每个应用程序中查找并进行更改,只需要更改存储过程即可。
一旦保存并编译,所有调用程序都会从更改中受益。同样,这有助于提高数据库的质量。
可以设置数据库安全性,以便应用程序只能通过存储过程调用来访问和修改数据。不允许进行即席查询或直接访问表。
安全访问也可以委托。实际上,存储过程代码是使用比调用者更高的访问凭据执行的。这意味着不必为需要调用存储过程的每个用户授予所有访问权限。例如,在SQL Server中,可以在创建存储过程时使用EXECUTE AS子句来模拟另一个用户。
使用存储过程还有助于防止脚本注入攻击。任何输入参数都被视为字面值而不是可执行代码。这使得攻击者更难尝试欺骗查询执行意外操作。
使用存储过程有一些缺点,会发现一些博客文章鼓励不要使用它们。认为值得一提一些缺点:
存储过程是用特定于供应商的语言编写的,这使得将它们从一个安装(如Oracle)转移到另一个(如SQL Server)变得困难。
测试和调试存储过程可能很棘手。构建允许逐步执行和跟踪存储过程的调试工具可能更加困难。与2000年代初相比,情况肯定有所改善,但仍然不如调试本地代码那样容易。
跟踪对存储过程所做的更改比跟踪本地源代码更加困难。与大多数本地代码IDE不同,将源代码控制集成到存储过程开发工具中的方法并不多。因此,大多数版本控制活动仅限于提取存储过程作为CREATE PROCEDURE脚本,然后手动导入到版本控制系统中。
认为存储过程有其位置。构建了一些广泛的应用程序,并使用了存储过程来处理所有CRUD操作。认为使用存储过程来插入和修改数据是一个很好的主意。
看到编写的广泛使用存储过程的系统通过了安全测试,并且不太可能引发漏洞测试问题。