【发布时间】:2021-08-09 07:31:33
【问题描述】:
我正在为一个客户端替换一个经典的 ASP 网站和 VB6 后端进程。这是一个非常高流量的站点,各种进程将记录插入到队列表中。几个进程是不同的 Web 服务,一个进程是经典 ASP 网站上的表单。对于新进程,我创建了一个调用存储过程的AFTER INSERT 触发器,该存储过程对另一个服务器进行 API 调用。该 API 调用将启动代码来处理新记录。这是INSERT(免责声明:修改代码以掩盖客户身份......让我看起来尽可能聪明):
-- =============================================
-- Author: Gary Jorgenson, RN
-- Create date: 05/17/2021
-- Description: notify system of New record
-- =============================================
CREATE TRIGGER [dbo].[tr_notify_new_record]
ON [dbo].[TableName]
AFTER INSERT
AS
BEGIN
DECLARE @id AS INT;
SELECT @id = I.id FROM INSERTED I
EXEC [dbo].[core_api_notify_new_record]
@record_id = @id
END
存储过程如下:
-- =============================================
-- Author: Gary Jorgenson, RN
-- Create date: 5/16/2021
-- Description: Notify system of new record
-- =============================================
CREATE PROCEDURE [dbo].[usp_api_newrecord_notify]
@record_id AS INT
AS
BEGIN
DECLARE @URL NVARCHAR(128) = 'https://ourwebsite.com/api/newrecord';
DECLARE @recID AS VARCHAR(50) = CONVERT(VARCHAR(50), @record_id);
SET @URL = CONCAT(@url, '/', @recID);
DECLARE @Object AS INT;
DECLARE @ResponseText AS VARCHAR(8000);
EXEC sp_OACreate 'MSXML2.XMLHTTP', @Object OUT;
EXEC sp_OAMethod @Object, 'open', NULL, 'post', @URL,'false'
EXEC [sp_OAMethod] @Object , 'setRequestHeader' , NULL , 'Content-Type' , 'application/json'
EXEC [sp_OAMethod] @Object , 'responseText' , @ResponseText OUTPUT
SELECT @ResponseText AS [Details]
EXEC [sp_OADestroy] @Object
END
为了进行初始测试,我让 API 控制器只是简单地插入到记录新创建记录的记录 ID 的日志表中。我使用 POSTMAN 在本地测试了 API,并且成功了。然后我锁定了 sp_OA... 方法以仅提供必要的权限,并通过使用与生产中使用的相同凭据在 SSMS 中执行存储过程来测试存储过程,这很成功。最后,我启用了AFTER INSERT 触发器,它非常自信地不会出错。
我错了。
打开触发器几分钟后,一些客户打电话报告说网站在尝试提交表单时崩溃了。与最初的网站开发人员合作,我们确定他的代码正在执行多语句 SQL 插入,其中最后一条语句调用 @@IDENTITY 以获取新记录 ID。不知何故,存储过程和/或 API 调用影响了@@IDENTITY,它返回了一个空值或零值。
这是没有意义的,因为在这个过程中唯一的其他 INSERT 是在 API 控制器后面,它在不同的机器上,在不同的 SQL Server 实例中插入日志记录。
原来的网站开发者将@@IDENTITY改为使用SCOPE_IDENTITY()。我们将进行测试,看看这是否能缓解问题。整件事让我感到紧张,因为我从没想过这个过程会对@@IDENTITY 产生任何影响,因为我没有在本地机器上的任何表中插入任何记录。我想更好地了解这个过程中发生了什么。
最后我的问题是,我的流程如何影响@@IDENTITY,因为我没有插入任何记录?
非常感谢任何建议!
【问题讨论】:
-
好点,谢谢。我将修改触发器以不将任何 id 传递给 proc,并让 proc 扫描新记录。抱歉的问题不是更清楚。我想知道当我没有在我的流程中创建任何新记录时,我的流程如何影响@@IDENTITY。
-
另外,我的代码中没有使用@@IDENTITY。这是我的新流程破坏的其他人编写的遗留代码。我的第一反应是询问原始开发人员是否可以将 @@IDENTITY 更改为 IDENT_CURRENT(tableName)
-
即使插入在另一台机器上,在完全不同的 SQL Server 实例中?
-
啊!这就说得通了。我没有考虑将未知插入到系统表中,这促使我在这里发帖。我的代码引起了我认为不应该引起的事情。我会将您关于 @@IDENTITY 的建议转达给其他开发人员,因为我无法更改他的代码。
-
您的触发器中有一个根本性错误:它假定
inserted中只有一行,这根本不正确,请参阅brentozar.com/archive/2019/05/…。另外,你真的不应该使用sp_OA...过程,因为它们很古老并且有很多问题,绝对不要在触发器中使用它们,因为事务将锁定直到收到响应
标签: sql-server tsql stored-procedures triggers webapi