27,578
社区成员




ALTER PROC [dbo].[Insert]
@Tid Int
AS
BEGIN
IF NOT EXISTS(SELECT 1 FROM Table WHERE TId = @Tid)
BEGIN
INSERT INTO Table (
INSERTDATE,
TID
)
VALUES (
GETDATE(),
@Tid
);
END
END
--CREATE TABLE test (INSERTDATE datetime,TID int )
create PROC [dbo].[Insert]
@Tid Int
AS
BEGIN
IF NOT EXISTS(SELECT 1 FROM test WHERE TId = @Tid)
BEGIN
INSERT INTO test (
INSERTDATE,
TID
)
VALUES (
GETDATE(),
@Tid
);
END
END
[Insert] 1
SELECT * FROM test
/*
INSERTDATE TID
----------------------- -----------
2014-05-27 10:20:13.350 1
*/
create table t
(
id int,
Createdate datetime
)
create index index_1 on t(id,createdate)
alter proc test_p
@i int
as
begin
begin tran
if not exists(select 1 from t with(xlock,rowlock) where id=@i )
begin
insert into t values (@i,GETDATE());
end
commit
end
--执行调用方式
declare @i int
set @i=cast( rand()*100000 as int)
exec test_p @i
然后用
select COUNT(1),id,Createdate from t
group by id,Createdate
having(COUNT(1))>1
来判断是否存在重复数据
select不做任何提示的时候,1000循环*30线程重复的很多,就不说了
当select中用(xlock,rowlock)锁提示的时候,竟然还有极个别重复的
用tablockx就没有了
当然你的那种方式也是没有问题的,我稍微改了一下,加了个top 1,如下,要不然是死循环
alter proc test_p
@i int
as
begin
INSERT INTO t
( id, Createdate )
SELECT top 1 @i, GETDATE() FROM test
WHERE NOT EXISTS ( SELECT 1 FROM t WHERE id = @i )
end
还请版主指教,为啥
begin tran
if not exists(select 1 from t with(xlock,rowlock) where id=@i )
begin
insert into t values (@i,GETDATE());
end
commit
这种方式是不行的,还是锁不住?
我在手动测试的时候,第一个窗口
begin tran
if not exists(select 1 from t with(xlock,rowlock) where id=12345)
begin
insert into t values (12345,GETDATE());
end
不提交,同样的脚本,第二个窗口中就被阻塞了,按道理也是没问题的啊
--查了一下,说是在锁定键上建立唯一索引(约束)xlock,rowlock才有效
--我测了一下,好像也是的,如下修改存储过程,为了防止还有重复的,UI上也反馈不出来,特意加了个异常的处理,
--如果异常,则记录下来,反反复复测试了即便,2000次循环*30线程,
--结果是预期的,没有重复的
--不知道能否说明这个问题:锁定键上建立唯一索引(约束)xlock,rowlock才有效?
--锁这块一直没弄清楚,我的理解应该分两类吧,范围和锁定方式,
--像tablock,rowlock这些事范围,xlock,updlock这些事锁定方式
--不知道对不对?
drop index index_1 on t
create unique index index_1 on t(id,createdate)
truncate table t
create table logmsg(id int,msg nvarchar(100))
alter proc test_p
@i int
as
begin
begin try
begin tran
if not exists(select 1 from t with(xlock,rowlock) where id=@i )
begin
insert into t values (@i,GETDATE());
end
commit
end try
begin catch
insert into logmsg values (@i,'数据重复异常');
end catch
end
select COUNT(1),id,Createdate from t
group by id,Createdate
having(COUNT(1))>1
select * from logmsg
但如果楼主是高并发的情况下,这样会导致数据丢失的吧,高并发产生的数据不一定都是重复无用数据[/quote]不会丢失,只把不存在的数据插入,逻辑来说和你的一样,只是插入的过程直接判断[/quote]
我是这样测试的,如下,写了一个存储过程,用sqlquerystress来开循环和线程
create table t
(
id int,
Createdate datetime
)
create index index_1 on t(id,createdate)
alter proc test_p
@i int
as
begin
begin tran
if not exists(select 1 from t with(xlock,rowlock) where id=@i )
begin
insert into t values (@i,GETDATE());
end
commit
end
--执行调用方式
declare @i int
set @i=cast( rand()*100000 as int)
exec test_p @i
然后用
select COUNT(1),id,Createdate from t
group by id,Createdate
having(COUNT(1))>1
来判断是否存在重复数据
select不做任何提示的时候,1000循环*30线程重复的很多,就不说了
当select中用(xlock,rowlock)锁提示的时候,竟然还有极个别重复的
用tablockx就没有了
当然你的那种方式也是没有问题的,我稍微改了一下,加了个top 1,如下,要不然是死循环
alter proc test_p
@i int
as
begin
INSERT INTO t
( id, Createdate )
SELECT top 1 @i, GETDATE() FROM test
WHERE NOT EXISTS ( SELECT 1 FROM t WHERE id = @i )
end
还请版主指教,为啥
begin tran
if not exists(select 1 from t with(xlock,rowlock) where id=@i )
begin
insert into t values (@i,GETDATE());
end
commit
这种方式是不行的,还是锁不住?
我在手动测试的时候,第一个窗口
begin tran
if not exists(select 1 from t with(xlock,rowlock) where id=12345)
begin
insert into t values (12345,GETDATE());
end
不提交,同样的脚本,第二个窗口中就被阻塞了,按道理也是没问题的啊
create table t
(
id int,
Createdate datetime
)
create index index_1 on t(id,createdate)
alter proc test_p
@i int
as
begin
begin tran
if not exists(select 1 from t with(xlock,rowlock) where id=@i )
begin
insert into t values (@i,GETDATE());
end
commit
end
--执行调用方式
declare @i int
set @i=cast( rand()*100000 as int)
exec test_p @i
然后用
select COUNT(1),id,Createdate from t
group by id,Createdate
having(COUNT(1))>1
来判断是否存在重复数据
select不做任何提示的时候,1000循环*30线程重复的很多,就不说了
当select中用(xlock,rowlock)锁提示的时候,竟然还有极个别重复的
用tablockx就没有了
当然你的那种方式也是没有问题的,我稍微改了一下,加了个top 1,如下,要不然是死循环
alter proc test_p
@i int
as
begin
INSERT INTO t
( id, Createdate )
SELECT top 1 @i, GETDATE() FROM test
WHERE NOT EXISTS ( SELECT 1 FROM t WHERE id = @i )
end
还请版主指教,为啥
begin tran
if not exists(select 1 from t with(xlock,rowlock) where id=@i )
begin
insert into t values (@i,GETDATE());
end
commit
这种方式是不行的,还是锁不住?
我在手动测试的时候,第一个窗口
begin tran
if not exists(select 1 from t with(xlock,rowlock) where id=12345)
begin
insert into t values (12345,GETDATE());
end
不提交,同样的脚本,第二个窗口中就被阻塞了,按道理也是没问题的啊
create table t
(
id int,
Createdate datetime
)
create index index_1 on t(id,createdate)
alter proc test_p
@i int
as
begin
begin tran
if not exists(select 1 from t with(xlock,rowlock) where id=@i )
begin
insert into t values (@i,GETDATE());
end
commit
end
--执行调用方式
declare @i int
set @i=cast( rand()*100000 as int)
exec test_p @i
然后用
select COUNT(1),id,Createdate from t
group by id,Createdate
having(COUNT(1))>1
来判断是否存在重复数据
select不做任何提示的时候,1000循环*30线程重复的很多,就不说了
当select中用(xlock,rowlock)锁提示的时候,竟然还有极个别重复的
用tablockx就没有了
当然你的那种方式也是没有问题的,我稍微改了一下,加了个top 1,如下,要不然是死循环
alter proc test_p
@i int
as
begin
INSERT INTO t
( id, Createdate )
SELECT top 1 @i, GETDATE() FROM test
WHERE NOT EXISTS ( SELECT 1 FROM t WHERE id = @i )
end
还请版主指教,为啥
begin tran
if not exists(select 1 from t with(xlock,rowlock) where id=@i )
begin
insert into t values (@i,GETDATE());
end
commit
这种方式是不行的,还是锁不住?
我在手动测试的时候,第一个窗口
begin tran
if not exists(select 1 from t with(xlock,rowlock) where id=12345)
begin
insert into t values (12345,GETDATE());
end
不提交,同样的脚本,第二个窗口中就被阻塞了,按道理也是没问题的啊