目前碰到一个问题,表A的ID列为整形自增列,由于项目需要需从该表获取一新ID,ID不能重复,获取ID和正常insert语句在并发时,存在ID重复情况,请高手们指点。 获取ID的SQL代码如下
DECLARE @nextId int; BEGIN TRANSACTION; SELECT @nextId=IDENT_CURRENT( '表名' ) +1; DBCC CHECKIDENT( '表名',RESEED, @nextId); SELECT @nextId; COMMIT TRANSACTION;
本问题的主要目的是如何控制用户A执行INSERT时,用户B获取表ID并设置ID种子增1,两者ID不重复?
------------------------
20120818
谢谢各位的回复,目前尚未得到满意答案,问题继续等待高手解决。
select @@identity
谢谢您的回答。以上语句是在插入数据后获取到当前值,但我只需ID值,不想做数据插入操作,同时这个ID种子还需增加,否则的话,通过insert插入数据时,就会存在重复了。
@Shijun.Huang.HI: 直接查询当前identity那一列最大的值。再加一。
要不不要自动增长,主键从主键表里取,取主键值的方法加上锁,同时只能执行一份。
数据还没有写入之前,多次取得的ID肯定都是相同的,并发肯定会有问题,为什么不把取ID的操作放在写入数据写入之后呢?
因写业务数据不在该表,无法写后取ID,仅用此表做唯一ID系列,数据在特定情况下会移到此表。出现情况,主要是A做INSERT,而同时B在做获取ID并增1操作,并发两者ID重复了。
GUID
回复内容太短(最少5个字),再写点吧!
GUID的确不存在此问题,但是可惜早期设计成这样,不太好修改
@Shijun.Huang.HI: 我可以理解为你要完成的是一个批量插入的功能么?先得到不重复的ID,但是不插入,然后等缓存到了一定数量的数据的时候批量插入?
@CrazyJinn: 也可以这么理解,但不是插入到该表,而是其他相似表
insert into 表名(...) output inserted.列名 values(...)
1 -- 回滚事务,不会回滚已经自增的ID 2 3 USE tempdb 4 5 IF OBJECT_ID('t1','U') IS NOT NULL DROP TABLE t1 6 7 CREATE TABLE t1(c1 INT NOT NULL IDENTITY) 8 9 INSERT INTO t1 DEFAULT VALUES 10 SELECT SCOPE_IDENTITY() -- 1 11 SELECT * FROM t1 -- 1 12 13 INSERT INTO t1 DEFAULT VALUES 14 SELECT SCOPE_IDENTITY() -- 2 15 SELECT * FROM t1 -- 1,2 16 17 BEGIN TRAN 18 INSERT INTO t1 DEFAULT VALUES 19 ROLLBACK 20 21 SELECT SCOPE_IDENTITY() -- 3 22 SELECT * FROM t1 -- 1,2 23 24 INSERT INTO t1 DEFAULT VALUES 25 SELECT SCOPE_IDENTITY() -- 4 26 SELECT * FROM t1 -- 1,2,4
在插入数据时加事务,锁住该表,避免幻读,设置事务的最高隔离级别set tran isolation level serializable
仅供参考
需要锁住这个表,同时只能有一个用户操作该表
需要锁住这个表,同时只能有一个用户操作该表
如果存在很多用户操作的时候,不建议使用锁表
建议还是使用自增ID
下面的语句是每次新增或者更新的时候抛出自增ID 无需锁表
IF Not Exists(Select Top 1 ID From EL_Datas Where DataName=@DataName) INSERT INTO EL_Datas(DataHtml,DataName,DataType,SelA,SelB,SelC,SelD,Rst,Score,Comps,Depts,Cats,CrtUser) OUTPUT inserted.ID SELECT @DataHtml,@DataName,@DataType,@SelA,@SelB,@SelC,@SelD,@Rst,@Score,@Comps,@Depts,@Cats,@CrtUser ELSE UPDATE EL_Datas SET DataHtml=@DataHtml,DataType=@DataType,SelA=@SelA,SelB=@SelB,SelC=@SelC,SelD=@SelD,Rst=@Rst,Score=@Score,Comps=@Comps,Depts=@Depts,Cats=@Cats,LstMdfUser=@LstMdfUser,LstMdfDate=getdate() OUTPUT inserted.ID Where DataName=@DataName
本问题关键不在此,谢谢回复
@Shijun.Huang.HI:
不能在表A先插入一笔空值取回ID吗?在A表多加入一个字段,IsUse(Bit) 默认值为0
如果想减少空值行记录,可以增加用户/IP字段。
逻辑:
1、先插入一行空值,获取ID值。
判断IsUser记录,如果为空则插入空值,不为空则取第一笔空值行ID
2、更新该ID行记录
设置IsUse为True
注意,这个逻辑能解决ID重复问题,但是可能出现空值行记录 以及 内容更新时间不按ID排序。
如果这样不能解决,那你只能锁表了。