设:表[T]有一字段num,int类型
---- ------
[id] [num]
1 1
存储过程如下:
begin tran
declare @N int
select @N=[num] from [T] where [id]=1
if(@N<2)
update [T] set [num]=[num]+1 where [id]=1
commit tran要求:执行完存储过程后,表中的num值不能大于2,但如果有两个用户同一时间执行上面存储过程的话,就会出现num的值为3.
请教如果解决?注意:请不要将select和update写成一句
---- ------
[id] [num]
1 1
存储过程如下:
begin tran
declare @N int
select @N=[num] from [T] where [id]=1
if(@N<2)
update [T] set [num]=[num]+1 where [id]=1
commit tran要求:执行完存储过程后,表中的num值不能大于2,但如果有两个用户同一时间执行上面存储过程的话,就会出现num的值为3.
请教如果解决?注意:请不要将select和update写成一句
解决方案 »
- update 多表net ,c#
- 作业可以指定时间运行吗?已经建立的作业可以修改吗?。。。。
- 标识异常增加
- 在sql2005中,还原增量数据备份文件时,出现“无法还原日志备份或差异备份,因为没有文件可用于前滚”是怎么回事
- 关于2010年计算机等级考试四级数据库考试那里有模拟题啊
- 有关数据并发处理问题 (zjcxc(邹建) 和zhangzs8896(小二) !斑主
- 怎样限制SQL Query Analyzer不能登陆数据库
- 数据库的问题 ~~~~请教高手 50分献上
- 两台机器的SQL Server2000数据库同步的问题
- sql server 2000里面datetime一天也是1么?
- TSQL debug: 高手请进
- 我又来了,这次是关于物资库存盘点的统计,对高手来说很容易,谢谢
--是这个意思吗?没发现问题啊...
create table t(id int, num int)
insert into t
select 1,1
begin tran
declare @N int
select @N=[num] from [T] where [id]=1
if(@N<2)
update [T] set [num]=[num]+1 where [id]=1
commit tran
begin tran
declare @n1 int
select @n1=[num] from [T] where [id]=1
if(@n1<2)
update [T] set [num]=[num]+1 where [id]=1
commit tran
begin tran
declare @N int
select @N=[num] from [T] where [id]=1--两用户同一时间点执行存储过程,取得@N的值都为1
if(@N<2)--都符合此条件
update [T] set [num]=[num]+1 where [id]=1--两用户都执行了这句,num的值变为了3
commit tran
设table1(A,B,C)
A B C
a1 b1 c1
a2 b2 c2
a3 b3 c3
1)排它锁
新建两个连接
在第一个连接中执行以下语句
begin tran
update table1
set A='aa'
where B='b2'
waitfor delay '00:00:30' --等待30秒
commit tran
在第二个连接中执行以下语句
begin tran
select * from table1
where B='b2'
commit tran
若同时执行上述两个语句,则select查询必须等待update执行完毕才能执行即要等待30秒
2)共享锁
在第一个连接中执行以下语句
begin tran
select * from table1 holdlock -holdlock人为加锁
where B='b2'
waitfor delay '00:00:30' --等待30秒
commit tran
在第二个连接中执行以下语句
begin tran
select A,C from table1
where B='b2'
update table1
set A='aa'
where B='b2'
commit tran
若同时执行上述两个语句,则第二个连接中的select查询可以执行
而update必须等待第一个连接中的共享锁结束后才能执行 即要等待30秒
3)死锁
增设table2(D,E)
D E
d1 e1
d2 e2
在第一个连接中执行以下语句
begin tran
update table1
set A='aa'
where B='b2'
waitfor delay '00:00:30'
update table2
set D='d5'
where E='e1'
commit tran
在第二个连接中执行以下语句
begin tran
update table2
set D='d5'
where E='e1'
waitfor delay '00:00:10'
update table1
set A='aa'
where B='b2'
commit tran
同时执行,系统会检测出死锁,并中止进程
1 如何锁一个表的某一行
A 连接中执行
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
begin tran
select * from tablename with (rowlock) where id=3
waitfor delay '00:00:05'
commit tran
B连接中如果执行
update tablename set colname='10' where id=3 --则要等待5秒
update tablename set colname='10' where id<>3 --可立即执行
--试试这样,看会不会发生你说的情况....
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
begin tran
declare @N int
select @N=[num] from [T] with (rowlock) where [id]=1
if(@N<2)
update [T] set [num]=[num]+1 where [id]=1
commit tran
declare @N int
select @N=[num] from [T] with WITH (ROWLOCK XLOCK readpast) where [id]=1
if(@N<2)
update [T] set [num]=[num]+1 where [id]=1
commit tran
declare @N int
select @N=[num] from [T] with (ROWLOCK XLOCK readpast) where [id]=1
if(@N<2)
update [T] set [num]=[num]+1 where [id]=1
commit tran
第一个用户开始:
begin tran
declare @N int
select @N=[num] from [T] where [id]=1
waitfor delay '00:00:10'
if(@N<2)
update [T] set [num]=[num]+1 where [id]=1
waitfor delay '00:00:05'
commit tran--然后,随着第二个用户开始:begin tran
declare @N int
select @N=[num] from [T] where [id]=1
waitfor delay '00:00:20'
if(@N<2)
update [T] set [num]=[num]+1 where [id]=1
commit tran
你自己在研究研究.
设置事务的隔离级别也可以.
参考:
数据库引擎中的隔离级别
http://msdn.microsoft.com/zh-cn/library/ms189122.aspx
select @N=[num] from [T] where [id]=1
改为:
select @N=[num] from [T] with(xlock,paglock) where [id]=1
用with(rowlock xlock readpast)也可以,这样第二个用户读到的是null,null和任意比都是else,同样达到了效果。
而指定页级锁就能够锁得行,使之不能放置共享锁.
并且用行级级锁,非要指定readpast锁才可以从侧面解决实际一些问题,在某些时候仍然不能使用。后来我才明白,行级锁对于sql server来讲,需要付出太多的代价,如果使用行锁,在同一个page里面的不同行进行更新时,极容易交错,而产生死锁,与其这样,如果直接使用页锁更为安全,但却损失了高并发性能,所以一般较强的服务器对于秒级的百个并发,处理都较为吃力。这是现在的理解,至于以后是否还有新理解,我还不知道。
对于未来,我不知道是继续着程序员,还是该做些什么,喝多了,大家原谅