当前位置: 代码迷 >> Sql Server >> 面试题:思考并发情况下,轮流指定病人取药的药房窗口的存储过程
  详细解决方案

面试题:思考并发情况下,轮流指定病人取药的药房窗口的存储过程

热度:21   发布时间:2016-04-24 19:08:25.0
面试题:考虑并发情况下,轮流指定病人取药的药房窗口的存储过程。
写一个类似发放扑克牌的存储过程,医院药房有6个窗口,病人交费的时候,
轮流指定取药窗口。要考虑并发问题和锁的问题。

表结构如下:

DrugRoomWindow(--表:药房窗口表,用以记录窗口开放状态和被选中状态
WindowID int ,--药房窗口号
WindowName nvarchar(20),--药房窗口名称
,IsActive bit ,--是否开放(高峰期6个窗口都开放,但其它时候可能只开放部分窗口)
IsSelected bit--选中状态
)

=============================================================
我写的存储过程如下,请问对表进行加锁,这样操作对吗?谢谢!
=============================================================

create procedure uspGetNextWindow
as
   select 1 from DrugRoomWindow with(TABLOCKX) --加锁使其它进程不能对表DrugRoomWindow进行读和写

   set @CurrentWindowID=(select top 1 WindowID from DrugRoomWindow where IsSelected=1)--当前排到哪个窗口      
   if @CurrentWindowID is null 
set @CurrentWindowID=1 --解决DrugRoomWindow初使状态所用记录的IsSelected=0的情况      
         
   set @NextWindowID=(select top 1 WindowID from DrugRoomWindow where WindowID>@CurrentWindowID and IsActive=1 
   and IsSelected<>1 order by WindowID)      
         
   if @NextWindowID is null      
   begin        
        --print '没有比它大的窗口,则取比当前窗口号小的最小窗口号'      
set @NextWindowID=(select top 1 WindowID from DrugRoomWindow 
where WindowID<@CurrentWindowID and IsActive=1 and IsSelected<>1 order by WindowID)       
   end           
end      
      
----------2、更新-----
set xact_abort on 
begin trans
update DrugRoomWindow set IsSelected=1 where WindowID=@NextWindowID      
update DrugRoomWindow set IsSelected=0 where WindowID<>@NextWindowID        
commit  
----------3、输出结果           
select * from DrugRoomWindow where WindowID=@NextWindowID--输出  
------解决方案--------------------
上面你已经使用了事务处理,再加上异常处理就可以了
begin try

end try
begin catch


end catch
------解决方案--------------------


--DROP TABLE DrugRoomWindow;
create table DrugRoomWindow(--表:药房窗口表,用以记录窗口开放状态和被选中状态
WindowID int ,--药房窗口号
WindowName nvarchar(20),--药房窗口名称
 IsActive bit ,--是否开放(高峰期6个窗口都开放,但其它时候可能只开放部分窗口)
IsSelected BIT,--选中状态
OrderNum INT, /*优选顺序*/
UseCount INT NOT NULL DEFAULT 0  
)
GO
INSERT INTO [dbo].[DrugRoomWindow] ([WindowID],[WindowName]
,[IsActive],[IsSelected],[OrderNum]) 
SELECT 10,'窗口10',1,0,10 union all
SELECT 20,'窗口20',1,0,20 union all
SELECT 30,'窗口30',1,0,30 union all
SELECT 40,'窗口40',1,0,40 union all
SELECT 50,'窗口50.此窗口特殊。排在最后被使用',1,0,60 union all
SELECT 60,'窗口60',1,0,50

--drop proc uspGetNextWindow;
GO

CREATE PROC uspGetNextWindow
AS
CREATE TABLE #tb(deWindowID INT)
UPDATE [DrugRoomWindow] SET IsSelected = 1,UseCount = UseCount+1
 OUTPUT DELETED.[WindowID] INTO #tb WHERE WindowID IN(
SELECT TOP 1 drw.WindowID FROM DrugRoomWindow drw 
WHERE drw.IsActive=1 /*开放的*/ and drw.IsSelected=0 /*未选中*/
ORDER BY drw.UseCount,drw.OrderNum
)
/*下一个可用的窗口。(没有结果集,则全部的窗口正忙,或全部的窗口被关闭)*/
SELECT * FROM [DrugRoomWindow] dw 
WHERE dw.WindowID=(SELECT deWindowID FROM #tb) 
GO


EXEC uspGetNextWindow


--楼主看一下我的是不是符合你的需求呢。我加了2上字段。
--如果关闭某些窗口时,请将UserCount字段值改为 开放窗口里最小的UserCount的值


  相关解决方案