我有这样一个存储过程,是用来做销售的:
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表是否为空)?
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表是否为空)?
解决方案 »
- 谁有MSSQL2008精简版本的MSSQL2005精简版本也行
- 有区别??????
- 求帮忙 写一条sql语句
- 做了一天了还差最后一步的sql语句求助
- 求Sql语句,我要查询ChinaSoft这个数年库中所有用户表记录数大于2000的用户表的表名?
- 连接查询的问题,急!
- 请教几个问题
- 如果使自动编号从新开始?
- 用那个工具能看到sql server收到了那些sql语句,以及个语句用了多少时间,我用的是sql2000?
- 同一產品分N次入庫,現在出庫一部分,我想按先進先出原則寫程序,沒動到的產品就不用列出來應該怎么寫
- 使用insert语句时,什么样的数据要加引号,什么样的数据不用加引号?
- sql语句能否只把中文表名列出来?
CREATE PROCEDURE [update_kc_minus]
(@czyname [varchar](50),
@doctorname [varchar](50)=null,
@djh int output)
AS
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE ----加了最高的隔离级别SERIALIZABLE
SET XACT_ABORT on
begin transaction xs ---- 事务开始
if exists(select 1 from kc with (TABLOCKX) 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表加有表级排他锁TABLOCKX
begin
delete salexm_temp1
commit transaction xs
RETURN 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 @djh=SCOPE_IDENTITY( ) --返回插入表sale时标识列返回的标识值给output
UPDATE [yd].[dbo].[salexm_temp1] SET xsdjh =@djh where xsdjh is NULL
INSERT INTO [yd].[dbo].[salexm] select * from [yd].[dbo].[salexm_temp1] where xsdjh=@djh
delete salexm_temp1
commit transaction xs --事务结束
end
GO
请问这样能解决并发问题,保证所有工作站同时调用这个存储过程,但在服务器执行时都是串行的,互不干扰吗?这样会不会发生死锁?