SQL Server 2008 Service Broker教程 - 无法接收消息(transmission_status中的异常)

pep*_*epr 23 service-broker sql-server-2008-r2

我正在学习如何使用SQL Server 2008 R2的Service Broker.在完成单个数据库中的完成对话教程时.在第1课之后,我成功创建了消息类型,合同,队列和服务.在第2课之后,我可能已经发送了这条消息.但是,在尝试接收消息时,我获取的是NULL ReceivedRequestMsg而不是发送的内容.

在查看时sys.transmission_queue,transmission_status消息说:

在目标队列中排队消息时发生异常.错误:15517,状态:1.无法作为数据库主体执行,因为主体"dbo"不存在,此类主体不能被模拟,或者您没有权限.

我已经使用Windows登录安装了SQL Server Mycomp\Petr.我也在使用该登录课程.

你能猜出是什么问题吗?我应该检查和设置什么才能使其正常工作?

编辑2012/07/16:为了帮助重现问题,这就是我所做的.如果您按照下一步操作,是否可以重现错误?

首先,我使用的是Windows 7 Enterprise SP1和Microsoft SQL Server 2008 R2,开发人员版,64位(版本10.50.2500.0,根目录位于C:\ Program Files\Microsoft SQL Server\MSSQL10_50.SQL_PRIKRYL05\MSSQL) .

  1. 按照教程建议,我下载了AdventureWorks2008R2_Data.mdf示例数据库,并将其复制到C:\ Program Files\Microsoft SQL Server\MSSQL10_50.SQL_PRIKRYL05\MSSQL\DATA\AdventureWorks2008R2_Data.mdf

  2. 必须以"管理员"身份启动SQL Server Management Studio才能以后附加数据.然后我连接了SQL Server.

  3. 右键单击Databases,上下文菜单Attach ...,按钮Add ...,指向AdventureWorks2008R2_Data.mdf + OK.然后从下面的网格中选择AdventureWorks2008R2_Log.ldf(报告为未找到)并按下删除...按钮.按OK后,附加了数据库并自动创建了AdventureWorks2008R2_log.LDF.

  4. 以下查询用于查看"Service Broker enabled/disabled",以及启用(Service Broker已成功启用数据库):


USE master;
GO

SELECT name, is_broker_enabled FROM sys.databases;
GO

ALTER DATABASE AdventureWorks2008R2
      SET ENABLE_BROKER
      WITH ROLLBACK IMMEDIATE;
GO

SELECT name, is_broker_enabled FROM sys.databases;
GO
Run Code Online (Sandbox Code Playgroud)
  • 然后,按照本教程,执行以下查询以创建消息类型,合同,队列和服务:

USE AdventureWorks2008R2;
GO

CREATE MESSAGE TYPE
       [//AWDB/1DBSample/RequestMessage]
       VALIDATION = WELL_FORMED_XML;
CREATE MESSAGE TYPE
       [//AWDB/1DBSample/ReplyMessage]
       VALIDATION = WELL_FORMED_XML;
GO

CREATE CONTRACT [//AWDB/1DBSample/SampleContract]
      ([//AWDB/1DBSample/RequestMessage]
       SENT BY INITIATOR,
       [//AWDB/1DBSample/ReplyMessage]
       SENT BY TARGET
      );
GO

CREATE QUEUE TargetQueue1DB;

CREATE SERVICE
       [//AWDB/1DBSample/TargetService]
       ON QUEUE TargetQueue1DB
       ([//AWDB/1DBSample/SampleContract]);
GO

CREATE QUEUE InitiatorQueue1DB;

CREATE SERVICE
       [//AWDB/1DBSample/InitiatorService]
       ON QUEUE InitiatorQueue1DB;
GO
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.

  • 然后使用以下查询来查看队列(使用时现在为空):

USE AdventureWorks2008R2;
GO

SELECT * FROM InitiatorQueue1DB WITH (NOLOCK);
SELECT * FROM TargetQueue1DB WITH (NOLOCK);
SELECT * FROM sys.transmission_queue;
GO
Run Code Online (Sandbox Code Playgroud)
  • 发送消息时会出现问题:

BEGIN TRANSACTION;

BEGIN DIALOG @InitDlgHandle
     FROM SERVICE
      [//AWDB/1DBSample/InitiatorService]
     TO SERVICE
      N'//AWDB/1DBSample/TargetService'
     ON CONTRACT
      [//AWDB/1DBSample/SampleContract]
     WITH
         ENCRYPTION = OFF;

SELECT @RequestMsg =
       N'<RequestMsg>Message for Target service.</RequestMsg>';

SEND ON CONVERSATION @InitDlgHandle
     MESSAGE TYPE 
     [//AWDB/1DBSample/RequestMessage]
     (@RequestMsg);

SELECT @RequestMsg AS SentRequestMsg;

COMMIT TRANSACTION;
GO  
Run Code Online (Sandbox Code Playgroud)

当在队列看时,Initiator...Target...队列是空的,并且可见于所发送的消息sys.transmission_queue经由报告上述的错误transmission_status.

Rem*_*anu 47

alter authorization on database::[<your_SSB_DB>] to [sa];
Run Code Online (Sandbox Code Playgroud)

EXECUTE AS基础结构需要dbo映射到有效的登录名.Service Broker使用EXECUTE AS基础结构来传递消息.遇到此问题的典型方案是在家工作时使用公司笔记本电脑.您使用缓存凭据登录到笔记本电脑,然后使用相同的Windows缓存凭据登录到SQL.您发出a CREATE DATABASE并将dbogets映射到您的公司域帐户.但是,EXECUTE AS基础架构无法使用Windows缓存帐户,它需要直接连接到Active Directory.令人抓狂的部分是第二天办公室工作正常(你的笔记本电脑再次进入公司网络,可以访问AD ......).你晚上回家,继续第3课......突然间它不再起作用了.使整个事情看起来脆弱和不可靠.只是需要AD锥度的事实......

导致相同问题的另一种情况是由于数据库CREATE DATABASE在恢复或附加时重新创建其创建者的SID(发出的Windows登录名)这一事实.如果您PC1\Fred在创建数据库时使用本地帐户,然后将数据库复制/附加到PC2,则该帐户在PC2上无效(当然,它的范围是PC1).同样,受影响的并不多,但EXECUTE AS是,这会导致Service Broker给出您看到的错误.

最后一个例子是当用户创建数据库时,该用户稍后离开公司并删除AD帐户.似乎从他的部分复仇,但他是无辜的.生产DB刚刚停止工作,只是因为这是他的 SID的dbo地图了.有趣的...

通过简单地改变dbosa登录你解决这整个EXECUTE AS的事情,所有依赖于它的运动部件(和SSB可能是最大的依赖)开始工作.

  • 就是这样!多谢。我还不明白细节,但它确实有效。亚瑟·C·克拉克:“任何足够先进的技术都与魔法没有区别。” ...如果人们不明白它是如何工作的。这样,你对我来说就是一个魔术师:) (2认同)

Ser*_*gey 5

您需要将目标队列的接收授予您的登录名.它应该工作!

USE [YourDatabase]
GRANT RECEIVE ON [dbo].[YourTargetQueue]
TO [Mycomp\Petr];
GO
Run Code Online (Sandbox Code Playgroud)

而且您还需要为您的用户授予发送权限,目标服务的权限应该足够,但是让我们在将来启用这两项服务.

USE AdventureWorks2008R2 ;
GO

GRANT SEND ON SERVICE::[//AWDB/1DBSample/InitiatorService]
TO [Mycomp\Petr] ;
GO

GRANT SEND ON SERVICE::[//AWDB/1DBSample/TargetService]
TO [Mycomp\Petr] ;
GO
Run Code Online (Sandbox Code Playgroud)