日期:2014-05-18  浏览次数:20538 次

在一个事务里其中一条语句中的表上加排他锁是否能保持到整个事务结束
我有这样一个存储过程,是用来做销售的:
CREATE PROCEDURE [update_kc_minus]
(@czyname [varchar](50),@doctorname [varchar](50)=null)
AS
SET XACT_ABORT on ---- 出错回滚
begin tran ---- 事务开始
 if exists(select 1 from kc with (xlock) inner join (select ypID,sum(sl) sl,rkdj from salexm_temp1 group by ypID,rkdj) a on kc.ypID=a.ypID and kc.rkdj=a.rkdj where kc.kcsl<a.sl) ---这句上的kc表加有排他锁xlock
  begin
  delete salexm_temp1 -----库存不足时清空表salexm_temp1 
  commit tran ----库存不足时结束事务
  RETURN 1 -----库存不足时返回1
  end
  else
  begin  
  UPDATE [yd].[dbo].[kc] SET kcsl=kc.kcsl-a.sl from kc inner join (select ypID,sum(sl) sl,rkdj from salexm_temp1 group by ypID,rkdj) a on kc.ypID=a.ypID and kc.rkdj=a.rkdj ---库存满足时改库存
  INSERT INTO [yd].[dbo].[sale] ( [doctorname], [czyname]) VALUES ( @doctorname,@czyname) 
  select SCOPE_IDENTITY( ) AS djh ----返回插入表sale时标识列返回的标识值:djh
  UPDATE [yd].[dbo].[salexm_temp1] SET xsdjh =SCOPE_IDENTITY( ) where xsdjh is NULL
  ------用返回的标识值:djh更新表salexm_temp1的xsdjh字段
  INSERT INTO [yd].[dbo].[salexm] select * from [yd].[dbo].[salexm_temp1] where xsdjh=SCOPE_IDENTITY( )  
  delete salexm_temp1 -----将salexm_temp1表中的内容插入表salexm中,并清空表salexm_temp1
  commit tran -----事务结束
  end 
GO
问题1:
  第一条判断库存的语句中在kc表上加的排他锁xlock(这样加锁不知道对不对)是否在整个事务(或存储过程)中都存在,还是第一条语句一结束就释放了kc表的资源。这个kc表上的排他锁是表级锁还是行级锁?如果始终存在,在C/S的并发情况下是否很容易发生死锁?
问题2:
  这个存储过程逻辑上有问题吗?特别是存储过程中那3个返回标识列值的“SCOPE_IDENTITY( )”在整个事务中返回的值是否始终保持一致?
问题3:当salexm_temp1表为空时,第一条判断库存的语句仍然会通过(认为库存满足),并执行else后面的语句,这样只有sale表会插入数据,其余表的内容不变。有什么其他的方法避免这种情况吗(不想在前面在加一条if语句以判断salexm_temp1表是否为空)?

------解决方案--------------------
可以通过设置事务的隔离级别来满足你的要求。默认的隔离级别是read committed