适用范围:SQL Server
Azure SQL 托管实例
Service Broker 采用会话组锁定功能保证在任何给定的时间只有一个队列读取器可以使用一组相关的消息。 Service Broker 采用会话组锁定功能保证按顺序处理这些消息,且仅处理一次。
所有的会话都属于会话组。 默认情况下,每个会话属于不同的会话组,因此具有不同的会话组标识符。 MOVE CONVERSATION 语句将更改会话的会话组。 BEGIN DIALOG CONVERSATION 语句包含用于将新会话与现有会话组相关联的选项。 有关会话组的详细信息,请参阅会话组。
实际上,会话组锁定是共享同一会话组标识符的消息组上的排他锁。 会话组锁定是以简单、高效和正确为宗旨而设计的。 不存在针对获取或释放会话组锁定的显式命令或提示, 而影响对话或会话组的每个 Service Broker 命令将会自动获取相应的会话组锁定。 例如,BEGIN DIALOG 语句将锁定包含新对话的会话组,而 RECEIVE 语句将锁定包含已收到的消息的会话组。
在会话已获取锁定的事务期间,会话对会话组保持锁定。 会话无法在多个事务中对会话组进行锁定,在事务结束时,将释放在该事务期间所获取的所有会话组锁定。
锁定将针对会话组而不是会话 ID 进行。 因此,即使发起方和接收方都位于同一数据库中,锁定也仅适用于会话的其中一方。 目标服务所获取的锁定不会阻塞起始服务,反之亦然。 此外,数据库引擎不会在将传入消息添加至队列时强制执行锁定。 即使应用程序对消息所属的会话组进行了锁定,数据库引擎也会将这些消息添加至队列。
实际上,这意味着仅使用从 Service Broker 检索的标识符的应用程序无需等待获取对 Service Broker 资源的锁定。 大多数 Service Broker 应用程序旨在利用 Service Broker 提供的锁定功能。 也就是说,大多数 Service Broker 应用程序仅使用已通过同一事务中的 Service Broker 语句获得的会话组标识符和会话句柄。
例如,应用程序通常从 Service Broker 获取会话组标识符,通过状态表检索状态,然后再处理该会话组中各个会话的消息。 应用程序在获取会话组标识符后,该应用程序即对会话组进行锁定:应用程序的其他实例无法获取该锁定。 但是,会话组锁定不会阻止应用程序的其他实例接收其他会话组的消息,也不会阻止传入消息到达队列。
通过此锁定策略,Service Broker 可以保证按顺序对消息进行处理。 因为只有一个队列读取器可以处理给定会话组的消息,所以不存在两个队列读取器同时接收同一会话组中的消息的风险。 对于特定会话,RECEIVE 语句将按发送消息的顺序返回消息,因此多个队列读取器可以处理该队列中的消息,而无需显式协调排序。
因为是对会话组而不是单个会话进行锁定,所以未使用 RECEIVE 语句指定特定会话的队列读取器可以接收属于同一会话组的不同会话中的消息。 此外,RECEIVE 语句将返回队列中的下一个可用消息,而不管该消息是否属于在当前事务中当前未锁定或锁定的会话组。 若要接收特定会话中的消息,请使用 RECEIVE 语句指定会话句柄。 若要接收特定会话组中的消息,请使用 RECEIVE 语句指定会话组标识符。
由于此锁定策略,您的应用程序应首先获取会话组锁定,然后才能更新应用程序的状态表。 大多数情况下,当您的应用程序接收消息或获取会话组时会自动执行此操作。 但是,处理错误时,应用程序可能需要重新获取会话组锁定,然后才能更新状态表以指示错误。 有关错误处理的详细信息,请参阅 Service Broker 的错误处理。
下列语句将获取会话组锁定: