快速回答是,您有两种选择来解决此问题:
- 修复您的存储过程,以便在并发情况下正确运行。
- 将 SQL 轮询接收处理程序放在群集 BizTalk 主机中。
下面是对正在发生的事情的解释,在此之下我给出了解决问题的实现细节:
解释
这是由于在多个主机实例上运行时 BizTalk 接收位置的工作方式(即,接收位置中指定的适配器的接收处理程序在具有多个主机实例的主机上运行)。
在这种情况下,两个主机实例都将运行它们的接收处理程序。
这通常不是问题 - 大多数接收适配器都可以管理它并为您提供您期望的行为。例如,文件适配器会在读取文件时锁定文件,防止重复读取。
这是一个问题的主要地方正是您所看到的 - 当轮询 SQL 接收位置命中存储过程时。在这种情况下,BizTalk 没有其他选择,只能信任 SQL 过程以提供正确的结果。
没有看到您的程序就很难判断,但是您查询记录的方式并不能保证唯一的读取。
也许你有类似的东西:
Select * From Record
Where Status = 'Unread'
Update Record
Set Status = 'Read'
Where Status = 'Unread'
上述过程可能会给出重复记录,因为在 select 和 update 之间,另一个 select 调用能够潜入并选择尚未更新的记录。
实施解决方案
修复程序
对该过程的一个简单修复是首先使用唯一 ID 进行更新:
Update Record
Set UpdateId = @@SPID, Status = 'Reading'
Where Status = 'Unread'
Select * From Record
Where UpdateId = @@SPID
And Status = 'Reading'
Update Record
Set Status = 'Read'
Where UpdateId = @@SPID
And Status = 'Reading'
@@SPID 应该是唯一的,但如果证明不是,您可以使用 newid()
使用集群主机
在创建新主机时,可以在 BizTalk 服务器管理控制台中指定该主机是群集的。Kent Weare在这篇文章中提供了有关执行此操作的详细信息。
基本上你像往常一样创建一个主机,在每台服务器上都有主机实例,然后右键单击主机并选择集群。
然后,您为在该主机下工作的轮询创建一个 SQL 接收处理程序,并在您的接收位置使用该处理程序。
BizTalk 群集主机确保作为该主机成员的所有项目一次将在一个且仅一个主机实例上运行。这将包括您的 SQL 接收位置,因此在调用您的过程时您不会有任何竞争条件的机会。