使用ServiceBroker自动激活模拟"秒杀"场景
1.简介
SQL Server Service Broker 是SQL server 里面比较独特的一个功能。它可帮助开发人员构建异步的松散耦合应用程序
ServiceBroker入门文章:http://blogs.msdn.com/b/apgcdsd/archive/2012/07/27/sql-server-service-broker-demo.aspx
ServiceBroker的队列存在自动激活(ACTIVATION)功能,其中内部激活可以激活数据库存储过程接受和处理队列的消息,而且可以启动激活存储过程的多个实例(MAX_QUEUE_READERS)。当SQLServer的SCHEDULER个数大于1(即多CPU)时,会有多个实例同时去接受并处理消息。
所以,接下来以发送出库消息,接受并更新库存为例,模拟并发条件下的库存检查及更新过程。
2.实现步骤
2.1 创建测试数据库及表
代码如下:其中inventory为库存表,表中两个字段,产品和库存数量
use master
create database wms
go
use wms
go
create table inventory(
material int,
quantity int
)
2.2 创建ServiceBroker对象,搭建基础框架
创建ServiceBroker服务对象,包括消息类型、约定、队列及服务等。简化起见,演示程序是运行在同一个数据库实例下的同一个数据库中
use wms
--创建消息类型
create message type inventoryio
--创建约定
create contract inventory_contract
(
inventoryio sent by initiator
)
--创建客户端队列
create queue inventory_client_queue
--创建客户端服务
create service inventory_client
on queue inventory_client_queue;
--创建库存队列
create queue inventoryio_queue
--创建库存更新服务
create service inventoryio
on queue inventoryio_queue
(
[inventory_contract]
);
2.3 开启会话,发送出库消息
--发送出库消息
begin transaction
declare @dialog_id uniqueidentifier
begin dialog conversation @dialog_id
from service inventory_client
to service 'inventoryio'
on contract [inventory_contract]
with encryption = off;
send on conversation @dialog_id message type inventoryio
(
'<InventoryUpdate>
<material>1</material>
<quantity>1</quantity>
</InventoryUpdate>'
);
commit transaction;
为了记下来测试并发情况,连续运行上面的代码四次。发送完后,查询目标服务的队列
select * from inventoryio_queue
结果如下:

2.4 创建库存更新的存储过程
接下里创建存储过程,该存储过程接受队列的出库指令,检查库存,当库存满足时,更新库存;库存不足时,回滚事务,消息重新回到队列
代码如下:
create proc InventoryProc as
begin transaction
declare @dialog_id uniqueidentifier
declare @message_body xml
declare @quantity int;
declare @material int; waitfor(
receive
@dialog_id = conversation_handle,
@message_body = message_body
from [dbo].inventoryio_queue),timeout 5000; if(@dialog_id is not null)
begin
set @quantity = @message_body.value('(/InventoryUpdate/quantity)[1]','int');
set @material = @message_body.value('(/InventoryUpdate/material)[1]','int');
--检查库存是否足够
if exists( select 1 from inventory where material = @material and quantity>=@quantity)
begin
print 'come here'
--更新库存
Update inventory set quantity =quantity-@quantity where material = @material;
end
else
begin
rollback
return
end
end
end conversation @dialog_id;
commit transaction;
go
2.5 修改队列,启用自动激活功能
启用队列的自动激活功能,激活的存储过程为上面创建的存储,设置最大读取器个数为5.
ALTER QUEUE [dbo].[inventoryio_queue] WITH STATUS = ON , RETENTION = OFF
, ACTIVATION ( STATUS = ON , PROCEDURE_NAME = [dbo].[InventoryProc]
, MAX_QUEUE_READERS = 5 , EXECUTE AS N'dbo' )
, POISON_MESSAGE_HANDLING (STATUS = OFF)
注意:
POISON_MESSAGE_HANDLING的设置必须为OFF,将有害消息处理设置为 OFF 的队列在五个连续的事务回滚之后不会被禁用。否则默认为ON,队列在回滚5次后,会被禁用 启用自动激活后,可以查看目前激活的实例
select * from sys.dm_broker_activated_tasks![]()
2.6 插入库存,查看更新结果
insert into inventory
values(1,1)
select * from inventoryio_queue
select * from inventory
结果如下:

可以看到队列中已经没有消息了,库存数量已经减少,但更新结果不准确.原因是在更新库存之前,多个存储过程实例都读取了库存数,并判断出库存满足,然后对库存进行了更新。
注:最终库存数量不一定为-3,需视Scheduler数量以及同时有多少个存储过程实例可以获得CPU来执行有关 解决方法:
一种是设置队列的自动激活的最大实例数为1,即不允许并发读取
另外就是在读取库存时,增加提示 with(holdlock),这样只允许一个实例读取库存表的一行数据,直到事务结束。
可查阅这篇文章:http://www.cnblogs.com/buaaboyi/archive/2011/08/30/2159860.html
代码如下:
--检查库存是否足够
if exists( select 1 from inventory with(holdlock) where material = @material and quantity>=@quantity)
3. 总结
本文演示了一个ServiceBroker单数据库的简单实例,并介绍了自动激活机制。简单涉及了SQLServer的CPU调度。同时,提及了SQLServer的 with(holdlock)提示
注:本文代码仅供演示使用而非实际应用于生产环境。如有问题及建议,请指正!^_^
参考文章:http://www.cnblogs.com/markj/archive/2013/03/31/2991777.html
使用ServiceBroker自动激活模拟"秒杀"场景的更多相关文章
- SQL SERVER 2014--内存表实现秒杀场景
===================================== 网上针对“秒杀”的解决方案很多,数据拆分化解热点,READPAST解决锁问题,应用程序排队限制并发等等很多方式,各有优缺点, ...
- springboot项目:Redis分布式锁的使用(模拟秒杀系统)
模拟秒杀系统: 第一步:编写Service package com.payease.service; /** * liuxiaoming * 2017-12-14 */ public interfac ...
- 秒杀场景下MySQL的低效(转)
秒杀场景下MySQL的低效 2016-01-14 17:12 178人阅读 评论(0) 收藏 举报 最近业务试水电商,接了一个秒杀的活.之前经常看到淘宝的同行们讨论秒杀,讨论电商,这次终于轮到我们自己 ...
- 【转载】秒杀场景下MySQL的低效原因和改进以及Redis的处理
分享的PPT在如下网址: http://www.doc88.com/p-4199037770087.html 秒杀场景下mysql的低效原因和改进 另外有一个篇文章是针对以上内容的总结: http:/ ...
- akka设计模式系列-akka在秒杀场景的应用
本博客讨论一下akka在秒杀场景下的应用,提出自己的见解,只做抛砖引玉,大神勿喷.秒杀活动涉及到前中后台各个阶段,为了说明问题,我们简化场景,只研究akka在后台如何处理秒杀业务. 秒杀活动 所谓的秒 ...
- synchronized、volatile区别、synchronized锁粒度、模拟死锁场景、原子性与可见性
synchronized.volatile区别.synchronized锁粒度 synchronized synchronized是Java中的关键字,是一种同步锁.有以下几种用法: 用法 1.修饰方 ...
- iwebshop模拟秒杀
//秒杀模拟练习public function sha(){ $testObj = new IModel("goodss"); $arr = $testObj->query( ...
- Jmeter(五十)_性能测试模拟真实场景下的用户操作
概述 我们在做性能测试的时候,不同的视角看到的结果都不一样. 例如响应时间 用户通过客户端向服务端发出请求的时间为: T1服务端接收到请求,处理该请求的时间为:T2服务端返回数据给客户端时间为: T3 ...
- Alibaba高并发业务秒杀系统落地实战文档,已实践某大型秒杀场景
前言: 高并发,几乎是每个程序员都想拥有的经验.原因很简单:随着流量变大,会遇到各种各样的技术问题,比如接口响应超时.CPU load升高.GC频繁.死锁.大数据量存储等等,这些问题能推动我们在技术深 ...
随机推荐
- ILSpy工具使用
Reflector是.NET开发中必备的反编译工具.即使没有用在反编译领域,也常常用它来检查程序集的命名规范,命名空间是否合理,组织类型的方法是否需要改善.举例说明,它有一个可以查看程序集完整名称的功 ...
- docker “no space left on device”问题定位解决
在paas环境上使用docker加载镜像的时候出现了如下问题 第一反应应该是存储镜像的路径磁盘满了 docker info查看docker的根路径,可以看到为/opt/docker: 查看/opt/d ...
- 机器学习--boosting家族之Adaboost算法
最近在系统研究集成学习,到Adaboost算法这块,一直不能理解,直到看到一篇博文,才有种豁然开朗的感觉,真的讲得特别好,原文地址是(http://blog.csdn.net/guyuealian/a ...
- 深入理解Java虚拟机:第2章 Java内存区域与内存溢出异常
目录 2.2 运行时数据区域 Java堆 方法区 虚拟机栈 本地方法栈 程序计数器 2.3 HotSpot虚拟机对象探秘 对象的创建 对象的内存布局 对象的访问定位 2.2 运行时数据区域 Jav ...
- kmean算法C++实现
kmean均值算法是一种最常见的聚类算法.算法实现简单,效果也比较好.kmean算法把n个对象划分成指定的k个簇,每个簇中所有对象的均值的平均值为该簇的聚点(中心). k均值算法有如下五个步骤: 随机 ...
- Node.js最新Web技术栈(2016年4月)
Node.js是比较简单的,只有你有前端js基础,那就按照我的办法来吧!一周足矣,虽然这版上了es语法,但依然是可以简单写,也可以难写,参见<全栈工程师之路-Node.js>,里面讲了No ...
- [转]Extending the User Interface in Outlook 2010
本文转自:https://msdn.microsoft.com/en-us/library/office/ee692172%28v=office.14%29.aspx#OfficeOLExtendin ...
- jQuery 1.9/2.0/2.1及其以上 on 无效的解决办法
jQuery 1.9/2.0/2.1及其以上版本无法使用live函数了,然而jQuery 1.9及其以上版本提供了on函数来代替.本文讲解了jQuery on函数的使用方法,以及在使用jQuery函数 ...
- 设计模式学习--面向对象的5条设计原则之接口隔离原则--ISP
一.ISP简介(ISP--Interface Segregation Principle): 使用多个专门的接口比使用单一的总接口要好.一个类对另外一个类的依赖性应当是建立在最小的接口上的.一个接口代 ...
- Oracle官网下载参考文档
最近有人问我有没有Oracle11g数据库官方参考文档,我就想,这不是在官网可以下载到的吗,疑惑,问了之后才知道,他官网找过,但时没有找到.不要笑,其实有很多人一样是找不到的,下面就一步一步操作下: ...