读书人

面试题:思忖并发情况下轮流指定病人

发布时间: 2014-01-25 22:37:26 作者: rapoo

面试题:考虑并发情况下,轮流指定病人取药的药房窗口的存储过程。
写一个类似发放扑克牌的存储过程,医院药房有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的值


读书人网 >SQL Server

热点推荐