你能从TSQL代码中调用Web服务吗?

39

有没有一种方法可以从TSQL存储过程或函数向Web服务发出调用?


虽然我不想这么做,但有时候你必须去做一些并不理想的事情。在这种情况下,我最终将 Web 服务函数重写为 SQL 函数以完成相同的任务。感谢您提供的所有链接和建议。 - TheEmirOfGroofunkistan
9个回答

35

是的,您可以这样创建

CREATE PROCEDURE CALLWEBSERVICE(@Para1 ,@Para2)
AS
BEGIN
    Declare @Object as Int;
    Declare @ResponseText as Varchar(8000);

    Exec sp_OACreate 'MSXML2.XMLHTTP', @Object OUT;
    Exec sp_OAMethod @Object, 'open', NULL, 'get', 'http://www.webservicex.com/stockquote.asmx/GetQuote?symbol=MSFT','false'
    Exec sp_OAMethod @Object, 'send'
    Exec sp_OAMethod @Object, 'responseText', @ResponseText OUTPUT
    Select @ResponseText
    Exec sp_OADestroy @Object
END

2
如何调用 HTTPS 服务? - abdulbasit
不要忘记重新配置MSSQL以启用对Web服务的调用。请参见下面的答案。我收到了一个错误:“SQL Server阻止访问组件“Ole Automation Procedures”的过程“sys.sp_OACreate”,因为该组件已关闭作为此服务器的安全配置的一部分。 系统管理员可以使用sp_configure启用“Ole Automation Procedures”的使用。 有关启用“Ole Automation Procedures”的更多信息,请在SQL Server Books Online中搜索“Ole Automation Procedures”。 - Jan

25

当然你可以,但这是一个可怕的想法。

由于web服务调用可能需要任意长的时间,并且会随机失败,这取决于你的网络上同时进行了多少盘反恐精英游戏,所以你无法确定这需要多长时间。

最起码,构建XML、发送HTTP请求到远程服务器,然后解析XML并发送响应需要半秒钟左右。

  1. 引发web服务的INSERT INTO BLAH查询的应用程序将不得不等待其完成。除非这只是类似每日计划任务的后台操作,否则您的应用程序性能将受到影响。

  2. web服务调用代码在SQL服务器内部运行,并使用它的资源。由于要等待HTTP请求很长时间,因此您将使用大量资源,这将再次损害服务器的性能。


9
+1 是指取决于您的网络同时进行了多少场反恐精英游戏,也感谢您提供好的答案。 ;) - Hilton Perantunes
6
如果你打算说这件事是可以做到的,那么你应该解释一下如何做到。 - Mark Bonafe
1
下面的回答者提供了一些有用的线索,并表达得非常好:“这两种架构都不像是合理的选择,但有时你必须做一些疯狂的事情。” - wunth
这是一个狭隘的观点和错误的答案,所讨论的工作站可能只需要每天、每周或每月访问一次,因此任何几秒或几分钟的延迟都是微不足道的,而且任何CPU使用也可以忽略不计。并非所有服务器都以24/7的100%运行。 - undefined
1
@Rostol 或许15年后我能更好地解释这个问题。 在SQL代码中调用Web服务是一个糟糕的主意,因为上面提到的性能原因,但正如你所说,如果你不关心性能,这些原因可以被合理化。更重要的原因是,这样做违反了其他开发人员的约定和期望。没有人会期望SQL去调用一个Web服务,所以当它这样做,并且出现问题时,你将会非常难以排查。 - undefined
@OrionEdwards 哈哈,15年后,我甚至都没注意到那个。谢谢你的回答。但是,我完全理解那种意想不到的“SQL Server自己连接到Web服务”的影响,即使使用外部dll。为该dll制作一个exe包装器是微不足道的。 - undefined

10

虽然T-SQL代码本身不支持,但使用SQL Server 2005及以上版本,可以编写CLR存储过程。CLR存储过程实质上是.NET代码中的函数,并将其公开为可用的存储过程。您可以在此过程中轻松访问大部分.NET框架,因此我可以看到可以通过此方法消费Web服务。

这里不方便详细讨论,但以下链接是关于该主题的MSDN文章


我还可以添加一篇更近期的(2009年5月)关于这个主题的文章:http://www.databasejournal.com/features/mssql/article.php/3821271/Calling-a-Web-Service-from-within-SQL-Server.htm - Hilton Perantunes

8

对于高流量或关键任务,我不会这样做。但是,如果您不需要从服务接收反馈,则实际上这是一件好事。

以下是我所做的一个示例。

  1. 触发器在表上进行插入和更新
  2. 触发器调用存储过程,将交易的JSON数据传递给Web Api端点,然后将其插入到AWS中的MongoDB中。

不要使用旧的XML。

JSON

EXEC sp_OACreate 'WinHttp.WinHttpRequest.5.1', @Object OUT;
EXEC sp_OAMethod @Object, 'Open', NULL, 'POST', 'http://server/api/method', 'false'
EXEC sp_OAMethod @Object, 'setRequestHeader', null, 'Content-Type', 'application/json'
DECLARE @len INT = len(@requestBody) 

完整示例:

Alter Procedure yoursprocname

 @WavName varchar(50),
 @Dnis char(4) 

    AS
BEGIN

    SET NOCOUNT ON;


DECLARE @Object INT;
DECLARE @Status INT;


DECLARE @requestBody NVARCHAR(MAX) = '{
"WavName": "{WavName}",
"Dnis": "{Dnis}"
}'


SET @requestBody = REPLACE(@requestBody, '{WavName}', @WavName)
SET @requestBody = REPLACE(@requestBody, '{Dnis}', @Dnis)


EXEC sp_OACreate 'WinHttp.WinHttpRequest.5.1', @Object OUT;
EXEC sp_OAMethod @Object, 'Open', NULL, 'POST',  'http://server/api/method', 'false'
EXEC sp_OAMethod @Object, 'setRequestHeader', null, 'Content-Type', 'application/json'
DECLARE @len INT = len(@requestBody) 
EXEC sp_OAMethod @Object, 'setRequestHeader', null, 'Content-Length', @len
EXEC sp_OAMethod @Object, 'send', null, @requestBody
EXEC sp_OAGetProperty @Object, 'Status', @Status OUT
EXEC sp_OADestroy @Object

1
谢谢您提供的示例。请也像@kiran.Backwad的示例一样包含 Exec sp_OADestroy @Object - TheEmirOfGroofunkistan
@TheEmirOfGroofunkistan,好的,这里有完整代码的帖子。 - Tom Stickel
有些人转向了CLR - 这很有效,所以我从来没有费心去替换sp_OA*调用。 - Tom Stickel
我使用这个脚本,但没有发送到Web服务。为什么呢!? - alireza

3

在早期版本的Sql中,您可以使用扩展存储过程或xp_cmdshell来外壳并调用Web服务。

虽然这两种方法都不像一个体面的架构 - 但有时您必须做一些疯狂的事情。


2
您可以通过嵌入的VB对象来实现它。 首先,创建一个类型为“MSXML2.XMLHttp”的VB对象,并将此一个对象用于所有查询(如果每次重新创建它,则会带来巨大的性能损失)。 然后,将该对象和一些参数传递给调用sp_OAMethod的存储过程。 很抱歉提供的示例不太明确,但是快速的谷歌搜索应该可以揭示vb-script方法如何完成。 -- 但CLR版本要简单得多...... 纠缠于web服务的问题在于它们无法跟上DB引擎的步伐。您会遇到许多错误,其中它只是跟不上步伐。 并且请记住,Web服务每次都需要新连接。重要性变得很大。您不希望打开5000个套接字连接来服务于表上的函数调用。那太疯狂了! 在这种情况下,您必须创建自定义聚合函数,并使用其作为传递给Web服务的参数,该服务将返回结果集......然后您必须整理它。这确实是一种获取数据的尴尬方式。

需要记住的是,使用嵌入式CLR比使用OLE对象性能要好得多,非常、非常、非常明显。我有一些小的CLR函数,由于客户的原因必须转换为调用OLE。一旦发生这种情况,性能就会受到巨大的影响。CLR函数在所有意义上都可以立即返回,但突然间每次调用需要近一秒钟才能返回。 - eidylon

2
这里有一个从Web服务获取数据的示例。在这种情况下,将用户代理字符串解析为JSON格式。
--first configure MSSQL to enable calling out to a webservice (1=true, 0=false)
sp_configure 'show advanced options', 1;  
GO  
RECONFIGURE;  
GO  
sp_configure 'Ole Automation Procedures', 1;  
GO  
RECONFIGURE;  
GO  

CREATE PROCEDURE CallWebAPI_ParseUserAgent @UserAgent VARCHAR(512)
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @Object INT;
    DECLARE @ResponseText AS VARCHAR(8000);
    DECLARE @url VARCHAR(512)

    SET @url = 'http://www.useragentstring.com/?getJSON=all&uas=' + @UserAgent;

    EXEC sp_OACreate 'WinHttp.WinHttpRequest.5.1', @Object OUT;
    EXEC sp_OAMethod @Object, 'Open', NULL, 'GET', @url, 'false'
    EXEC sp_OAMethod @Object, 'setRequestHeader', NULL, 'Content-Type', 'application/json'
    EXEC sp_OAMethod @Object, 'send'
    EXEC sp_OAMethod @Object, 'responseText', @ResponseText OUTPUT
    SELECT @ResponseText
    EXEC sp_OADestroy @Object
END

--example how to call the API
CallWebAPI_ParseUserAgent 'Mozilla/5.0 (Windows NT 6.2; rv:53.0) Gecko/20100101 Firefox/53.0'

1

1
我曾在全球大型公司工作,使用Oracle数据库。我们通过存储过程不断地使用Web服务,并且没有遇到任何问题,即使是那些访问量很大的服务。所有这些服务都是内部使用的,也就是说没有接入互联网,只能在工厂内部使用。我建议您使用它,但一定要非常小心地设计它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接