第七章 错误处理、测试、源代码管理和部署 本章涵盖处理 T-SQL 错误 代码故障排除 性能测试 现代开发实践 当人们想到数据库开发人员的角色时,很容易将注意力完全集中在编写高效的T-SQL代码上。然而,实际上,现代数据库开发人员必须考虑许多其他方面。错误处理是其中的第一个方面。如果一个过程在生产环境中抛出错误,我们希望能够优雅地处理该错误,以降低数据不一致等风险。错误处理甚至可以使代码重试,从而避免应用程序支持团队介入。我们也通常希望在错误发生时收到通知,以便进行调查。 我们还需要能够高效地调试代码错误。代码最终会有漏洞。这是生活的事实。当我们的代码中存在漏洞时,我们需要能够以高效的方式进行调试。如果写一段代码只需一天,但调试它却需要一周,那就毫无意义。因此,在处理复杂代码时,理解调试方法是至关重要的。 我经常看到SQL开发人员犯的一个常见错误是缺乏测试。我们将作为对SQL开发人员现代开发实践(缺乏)采用的更广泛的探讨的一部分来研究单元测试。我们将探讨将代码保存在源代码控制中、编写单元测试以及使用自动化构建和部署管道的好处。在第4章中,我们创建了一个名为MagicChoc的数据库,在第6章中,我们创建了一个名为Marketing的数据库。本章中我们将使用这两个数据库。 现代开发实践要求代码保存在源代码管理中,并使用 DevOps 流程来部署代码。这些实践多年来已经成为常态,但 SQL 开发人员似乎采用得较晚。我见过许多 SQL Server 团队仍将他们的“源代码”存储在数据库备份中,并手动运行复杂、精心制作的脚本来部署他们的数据层应用程序。本章中我们将探讨这两种错误。 开发工具 到目前为止,在本书中,除非我们探讨了 SQL Server 集成服务 (SSIS) 的时候,我一直在使用 SQL Server 管理工作室 (SSMS) 来创建示例,我假设你可能也一直在使用 SSMS 跟随操作。它对 SQL Server 专业人士来说非常熟悉,而且非常容易使用。 我们可以使用其他几种工具来开发 T-SQL,例如 Visual Studio Code、SQL Server 数据工具 (SSDT) 和 Azure Data Studio。对于一些高级开发技术,我们需要使用其中一些额外的开发工具。对于错误 错误26# 编写不处理错误的代码 如果我们的代码在生产环境中失败,最不希望发生的就是出现未处理的错误。如果我们的代码失败,我们希望它能够优雅地失败,并向应用支持团队提供有用的诊断信息,他们需要尝试解决问题。为了探讨这个问题,让我们首先查看一个没有错误处理的存储过程,并看看其中的一些后果。 清单7.1中的存储过程可以在MagicChoc数据库中创建。它是一个简单的存储过程,接受创建新销售订单所需的参数。它根据客户生成SalesOrderNumber所需的前缀,然后将记录插入到SalesOrderHeaders和SalesOrderDetails表中。 CREATE PROCEDURE dbo.InsertSalesOrder @SalesOrderNumber NVARCHAR(12), @SalesOrderDate DATE, @SalesPersonID INT, @SalesAreaID INT, @CustomerID INT, @SalesOrderDeliveryDueDate DATE, @SalesOrderDeliveryActualDate DATE, @CurrierUsedForDelivery NVARCHAR(32), @ProductID INT, @Quantity INT AS BEGIN BEGIN TRANSACTION DECLARE @CustomerPrefix NVARCHAR(12) ; SET @CustomerPrefix = ( SELECT SUBSTRING(CustomerCompanyName,1,3) FROM dbo.Customers WHERE CustomerID = @CustomerID ) ; INSERT INTO dbo.SalesOrderHeaders VALUES ( @CustomerPrefix + @SalesOrderNumber , @SalesOrderDate , @SalesPersonID , @SalesAreaID , @CustomerID , @SalesOrderDeliveryDueDate , @SalesOrderDeliveryActualDate , @CurrierUsedForDelivery ) ; INSERT INTO dbo.SalesOrderDetails ( ProductID , Quantity , SalesOrderNumber ) VALUES ( @ProductID , @Quantity , @CustomerPrefix + @SalesOrderNumber ) ; COMMIT END 让我们通过使用存储过程尝试创建一些销售订单来实践看看。下面清单中的脚本将执行我们的存储过程,销售订单将成功插入到 SalesOrderHeaders 和 SalesOrderDetails 表中。 EXEC dbo.InsertSalesOrder ‘1635D-U06’ , ‘2023-08-19’ , 1 , 1 , 2 , ‘2023-09-01’ , NULL , ‘Get Me There!’ , 5 , 1 ; 到目前为止,一切顺利!该过程运行成功,并且添加了一个销售订单。让我们使用清单7.3中的脚本再次执行存储过程。这一次,在执行存储过程之前,我们将把 SalesOrderDetails 表的名称更改为 SalesOrderLines。自然,这将在事务内部导致失败。 EXEC sp_rename ‘dbo.SalesOrderDetails’, ‘SalesOrderLines’ ; GO […]