积极答复者
一个多用户情形下的并发情况,疑惑中。。。

问题
-
现在要实现一个简单的功能,插入数据到表之前检查下是否已经存在,如果存在就update加个计数,不存在就直接insert.
SQL代码如下:
create a(id int,times int)
begin tran
update a set times=times+1 where id=@id
if @@rowcount=0
insert a(id,times)
select @id,@times
commit tran
这种写法在多用户频繁操作的情况,还是会存在重复插入的情况,都做了事务处理了,一直不明白为什么还有重复的现象呢?请大侠们答疑解惑,谢谢!
- 已编辑 zyyjc 2013年9月20日 11:49
答案
全部回复
-
-
LZ您好
方法一:
你可以在表a中的id字段建立一个唯一约束
方法二:
在插入记录之前判断一下,下面插入语句放在if @@rowcount=0的下面
DECLARE @id int DECLARE @times int SET @id=2 SET @times=2 insert a(id,times) select @id,@times where not exists(select * from a where id=@id)
方法三:
建立唯一索引
CREATE UNIQUE INDEX ix ON a(id)
--或
CREATE UNIQUE CLUSTERED INDEX ix ON a(id) -
你说的重复是id还是times?如果两个用户同时访问表,并且表中找不到这个ID,是否可以同时Insert呢?你自己测试一下找不到数据的时候是否可以并发。
Please Mark As Answer if it is helpful.
- 已编辑 KevinLiu328 2013年9月22日 2:50
-
你能给几个重复的数据吗?
Please Mark As Answer if it is helpful.
--存储过程
create proc up_a
@id int
as
begin tran
update a set times=times+1 where id=@id
if @@rowcount=0
insert a(id,times)
select @id,1
commit tran比如现在a表数据为空,当我在同一个时间点执行exec up_a @id=1这个存储过程时,如果a表没做唯一约束的话,会同时插入2条记录(要求同个id只有一条记录),除了设置约束和主键外,还有其它办法吗?
- 已编辑 zyyjc 2013年9月23日 10:04
-
如果你用 sql 2008, 可以考虑 merge 语句 merge a using(select id = @id) b on a.id = b.id where matched then update set times=a.times+1 when not matched by target then insert(id,times) values(@id,@times)
我再修正一下,邹建大侠有个地方写错了
USE [tempdb] GO CREATE TABLE a ( id INT, times INT ) GO INSERT INTO a(id,[times]) SELECT 1,1 UNION ALL SELECT 2,2 GO SELECT * FROM [dbo].[a] GO --如果你用 sql 2008, 可以考虑 merge 语句 DECLARE @id INT= 6 , @times INT= 10 MERGE a --目标表 USING ( SELECT id = @id) b --源表 ON a.id = b.id WHEN MATCHED THEN UPDATE SET a.times = @times WHEN NOT MATCHED BY TARGET THEN INSERT ( id, times ) VALUES ( @id ,@times );
更新
DECLARE @id INT= 2 , @times INT= 9 MERGE a --目标表 USING ( SELECT id = @id) b --源表 ON a.id = b.id WHEN MATCHED THEN UPDATE SET a.times = @times WHEN NOT MATCHED BY TARGET THEN INSERT ( id, times ) VALUES ( @id ,@times );