SQL Service Broker消息中的汉字

时间:2009-07-09 23:17:18

标签: sql-server tsql service-broker

我在数据库中设置了多个SQL Service Broker队列,但之前没有看到过这个问题。包含XML的消息正在转换为看似主要是中文字符的消息。当我在将它放入消息队列之前检查存储XML的变量时,我可以看到它是英文的并且形成了良好的XML。当我从队列中选择时,我会收到汉字。这些字符也是我从外部C#应用程序中拉出队列时收到的字符。奇怪的是,如果我使用DBArtisan查看队列,我会看到格式良好的XML。

下面的XML放在队列中时会转换成下面的中文字符

<?xml version="1.0" ?>
<Message>
  <MachineName>The Super Duper Machine</MachineName>
  <CollectionName>snl0013d</CollectionName>
  <Action>Install</Action>
  <EntryDateTime>Jul  9 2009  4:47PM</EntryDateTime>
</Message>

㼼浸敶獲潩㵮ㄢ〮•㸿਍†††䴼獥慳敧ാ
 †††㰠慍档湩乥浡㹥桔⁥畓数⁲畄数⁲慍档湩㱥䴯捡楨敮慎敭ാ
 †††㰠潃汬捥楴湯慎敭猾汮〰㌱㱤䌯汯敬瑣潩乮浡㹥਍
 ††††䄼瑣潩㹮湉瑳污㱬䄯瑣潩㹮
 ਍††††䔼瑮祲慄整楔敭䨾汵†‹〲㤰†㨵〱䵐⼼湅牴䑹瑡呥浩㹥਍
†††⼼敍獳条㹥

下面是我用来将消息放入队列并选择它的T-SQL。

declare @dialog_handle uniqueidentifier
       ,@msg varchar(max)
       ,@collection_name varchar(30)

set @collection_name = 'snl0013d'

set @msg =
N'<?xml version="1.0" ?>
  <Message>
    <MachineName>' + 'The Super Duper Machine' + '</MachineName>
    <CollectionName>' + @collection_name + '</CollectionName>
    <Action>' + 'Install' + '</Action>
    <EntryDateTime>' + CAST(getdate() AS VARCHAR(100)) + '</EntryDateTime>
  </Message>'

select @msg

set @dialog_handle = NEWID()
begin dialog conversation @dialog_handle
    from service [SAPP_QUEUE_ResponseService]
    to service 'SAPP_QUEUE_SubmitService'
    on contract [SAPP_CONTRACT_Contract]
    with encryption = off;

send on conversation @dialog_handle
  message type [SAPP_MSG_MessageType]
(
    @msg
);
end conversation @dialog_handle 
with cleanup

select message_body
      ,conversation_handle
      ,CONVERT(nvarchar(max), message_body) as msg
  from SAPP_QUEUE_SubmitQueue;

2 个答案:

答案 0 :(得分:7)

好的,这个答案不是主题,但我必须:请不要与服务经纪人做fire and forget。 begin-send-end消息模式存在许多问题,从无法解决对数据库的故障响应到脱机。后者是由于SSB(SQL Service Broker)中的一个错误,但我看到它发生了,它是由fire和forget消息模式引起的。

哦,还有一件事:我不知道DBArtisan是什么,但它认为你的ASCII消息是有效的,那么它意味着它将message_body列转换为varchar(max),这就是全部。

既然我的帖子已经很大了,那么我还要深入研究一下XML编码和SSB。您可能知道,如果您将消息类型[SAPP_MSG_MessageType]声明为VALIDATION = WELL_FORMED_XML,则SSB会提供XML消息验证。但ASCII和UNICODE都是有效的XML编码,并且SSB都支持这两种编码。您可以发送消息 N '<someTag>somecontent</someTag>'以及'<someTag>somecontent</someTag>',两者都是有效的XML代码段。您还可以添加声明编码的显式XML处理指令,例如<?xml version="1.0" encoding="utf-8"?> N <?xml version="1.0" encoding="utf-16"?>。但是,您将面临不匹配的风险,例如声明 N <?xml version="1.0" encoding="utf-8"?>,这实际上是无效的XML(因为声明的编码与文档编码不匹配)。您可以遇到各种非常微妙且难以解决的问题。这是一个完美的问题示例,它可以导致目标服务拒绝消息,并使用XML验证响应使对话失败,您将会错过这个响应,因为......您正在做“即发即弃”:) / p>

在我的实践中(我是MS的SQL Service Broekr团队的成员之一)我发现避免任何麻烦的最好方法是将包含sent(@ msg)的变量声明为类型xml ,不是varchar也不是nvarchar 。这样可以解决所有问题,并正确解决BOM in your XML的需要和存在问题。这也适用于传入的C#参数,最佳匹配是使用SqlXml类型和/或System.Data.SqlDbType.Xml枚举值。

同样在队列的接收端(您的激活过程或读取目标队列的进程),您应该将消息体转换为XML类型,而不是varchar / nvarchar。当我们讨论这个主题时,请确保在接收期间不要强制,但只有在接收之后才会因为XML error handling interacts with activation的方式而投射

答案 1 :(得分:5)

我不知道是不是这样,但我看到你使用nvarchar文字而是分配给varchar变量......