当前位置: 代码迷 >> Sql Server >> 存储过程同时插入两条雷同数据 插入时间完全相同
  详细解决方案

存储过程同时插入两条雷同数据 插入时间完全相同

热度:50   发布时间:2016-04-24 10:39:04.0
存储过程同时插入两条相同数据 插入时间完全相同
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



TID是其他表的主键,主要为了避免重复插入的

这是什么情况。。。

是代码的问题?

求解


------解决方案--------------------


--查了一下,说是在锁定键上建立唯一索引(约束)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



引用:
1、我是记得只有tablockx才能锁得住。
2、http://technet.microsoft.com/zh-cn/library/ms187373.aspx中有一句:获取行级别锁的锁提示 ROWLOCK、UPDLOCK 和 XLOCK 可能对索引键而不是实际的数据行采用锁。

Quote: 引用:

Quote: 引用:

Quote: 引用:

Quote: 引用:

把判断直接写在insert过程中,算一步,你那个写法算2步

但如果楼主是高并发的情况下,这样会导致数据丢失的吧,高并发产生的数据不一定都是重复无用数据
不会丢失,只把不存在的数据插入,逻辑来说和你的一样,只是插入的过程直接判断



我是这样测试的,如下,写了一个存储过程,用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,如下,要不然是死循环
  相关解决方案