3

我们有一个应用程序,它使用 Service Broker 在 SQL Server 中创建队列和服务来处理数据库通信。该应用程序使用这些服务并正确发送/接收消息,但我现在想测试这个应用程序的初始化阶段(它创建代理以及在幕后工作的存储过程)。基本上,我需要以某种频率删除代理元素,而且它现在真的很慢。

如果有帮助,我可以更改应用程序创建代理元素的方式 - 但这个问题与关闭所有内容更相关。

我用来关闭代理的代码是:

receive * from [dbo].[notify_initiator_queue]
alter queue [dbo].[notify_initiator_queue] with status = OFF
drop service [//DBNotifyService-Initiator]
drop queue [dbo].[notify_initiator_queue]
drop message types, contacts, etc...

这会在“drop service [//XF/DBNotifyService-Initiator]”上挂起一段时间。是否有更快的方法来关闭和删除服务代理的全部或部分元素?

谢谢!

==更新==

好的,我花了一些时间,但下面的答案确实解决了问题。我想为其他可能遇到问题的人澄清一下。

我的应用程序正确关闭了所有服务、队列、合同和消息。关闭服务需要很长时间,因为应用程序中的一个错误有一堆开放的对话。正在创建这些对话,用于发送消息,然后以以下方式结束:

END CONVERSATION @conversation with cleanup

'with cleanup' 位仅关闭对话的本地端(想想,它允许服务器清理任何可能在另一端出错的对话)。它不会关闭发送服务的另一端,因此对话保持打开状态。正常对话应该结束:

END CONVERSATION @conversation

这修复了应用程序错误。但是,我在数据库中有几百万次中断的对话。我可以像普通人一样删除数据库,或者我可以尝试弄清楚如何关闭它们。要一一关闭它们:

declare @conversation uniqueidentifier 
while exists (select top 1 conversation_handle from sys.transmission_queue ) 
begin 
  set @conversation = (select top 1 conversation_handle from sys.transmission_queue )
  end conversation @conversation with cleanup 
end

每个连接需要几毫秒(对于数百万来说非常慢)。如果我想快速关闭它们,请使用下面的答案并运行修改后的命令:

ALTER DATABASE [" + target.getTargetDbName() + "] SET NEW_BROKER WITH ROLLBACK IMMEDIATE;

with rollback immediate 使所有连接都断开,而不允许它们确保提交。文档说“所有未完成的事务都将被回滚,并且与 AdventureWorks2008R2 示例数据库的任何其他连接都将立即断开。” http://msdn.microsoft.com/en-us/library/bb522682.aspx

这些服务现在正在迅速下降,错误和打开的连接都消失了。

4

1 回答 1

6

原因很可能是因为这些元素被 SCH-S 锁锁定,因为它们正在使用中,从而阻止了您的 drop 语句。典型的罪魁祸首是在后台运行的激活程序。这可以通过检查活动监视器阻塞原因或查看来快速调查sys.dm_exec_requests。运行激活的程序可以在 中看到sys.dm_broker_activated_tasks

作为一种解决方法,您可以尝试ALTER DATABASE SET NEW_BROKER,它会丢弃所有现有的对话,但不会丢弃队列/服务/合同/消息类型。它还将更改当前数据库service_broker_instance_id(如果您在路线中使用它,这很重要)。通过删除所有对话,激活的程序应该自行关闭(如果它们被正确编写)。

但我会推荐一种不同的方法。与其让您的测试一次又一次地重用同一个数据库并处理“关闭”阶段的所有错误故障,不如始终从干净的数据库开始并在干净的数据库上运行部署脚本。这样您就不需要“删除”代码。请参阅版本控制和您的数据库。我们使用干净数据库的数据库备份并始终从该备份开始,还原它并部署您的应用程序,然后运行您的验证测试。

于 2011-08-03T18:23:17.530 回答