在并发事务中加锁的示例代码
来源:互联网 发布:联合大数据有限公司 编辑:程序博客网 时间:2024/05/22 17:48
create table stock(material int,quantity int)--库存表
insert stock select 1,100 union all select 2,20
create table stock_out(id int identity,material int,quantity int)--出库单表
go
--出库表插入触发器,用于检查可用库存,并更新库存表减库存。
create trigger tr_stock_out_i on stock_out
for insert
as
begin
set nocount on
if exists(select 1 from inserted _i join stock _s with(updlock) on _s.material = _i.material
where _i.quantity > _s.quantity
)
begin
raiserror('库存不够!',16,1)
rollback tran
return
end
else
begin
waitfor delay '00:00:05'--模拟并发事务
update _s set _s.quantity = _s.quantity - _i.quantity
from stock _s join inserted _i on _i.material = _s.material
end
end
go
--如果不加锁,在两个连接中分别执行
waitfor time '15:12'
insert stock_out(material,quantity)
select 1,100
--然后
select * from stock where material = 1
--得
/*
material quantity
----------- -----------
1 -100
库存出现负数,因为sql执行的顺序为
连接1检查库存,满足
连接2检查库存,满足
连接1减库存,减到0
连接2减库存,减到-100
检查库存与减库存这两个动作之间必须是无缝的,所以在检查库存时要加更新锁。
更新锁是自排斥的,并且与共享锁兼容,它会保持到事务结束即insert语句最外层的事务结束。
*/
go
drop table stock,stock_out