0

我在 C# 中创建了两个线程,并且并行调用了两个单独的函数。这两个函数都从 XYZ 表中读取最后一个 ID 并插入值为 ID+1 的新记录。这里 ID 列是主键。当我执行这两个函数时,我收到主键违规错误。这两个函数都具有以下查询:

insert into XYZ values((SELECT max(ID)+1 from XYZ),'Name') 

似乎这两个函数都在一次读取值并尝试插入相同的值。我怎么解决这个问题.. ?

4

4 回答 4

2

让数据库为您选择 ID。从上面的代码中可以明显看出,您真正想要的是一个自动递增的整数 ID 列,数据库绝对可以为您处理。所以正确设置你的表,而不是你当前的插入语句,这样做:

insert into XYZ values('Name') 

如果您的数据库表已经建立,我相信您可以发出类似于以下的语句:

alter table your_table modify column you_table_id int(size) auto_increment

最后,如果无论出于何种原因,这些解决方案都不适用(包括,如您在评论部分中指出的,无法编辑表架构),那么您可以按照评论中建议的其他用户之一进行操作,并创建一个同步方法来找到下一个 ID。您基本上只需创建一个返回 int 的静态方法,在该静态方法中发出您的 select id 语句,然后使用返回的结果将您的下一条记录插入到表中。由于此方法不能保证成功插入(由于外部应用程序也可以插入同一个表中),因此您还必须捕获异常并在失败时重试)。

于 2013-03-25T04:28:08.097 回答
2

将 ID 列设置为“身份”列。然后,您可以按以下方式执行查询:

insert into XYZ values('Name') 

我认为您不能在创建列后使用 ALTER TABLE 将列更改为身份。使用 Managament Studio 将此列设置为 Identity。如果您的表有很多行,这可能是一个长时间运行的过程,因为它实际上会将您的数据复制到一个新表(将执行表重新创建)。

该选项很可能在您的 Managament Studio 中被禁用。为了启用它,打开工具->选项->设计器并取消选中选项“防止保存需要重新创建表的更改”...根据您的表大小,您可能还必须设置超时。在此期间,您的桌子将被锁定。

于 2013-03-25T04:45:25.150 回答
0

此类问题的解决方案是使用某种序列生成 ID。

例如,在 SQL Server 中,您可以使用以下命令创建序列:

CREATE SEQUENCE Test.CountBy1
    START WITH 1
    INCREMENT BY 1 ;
GO

然后在 C# 中,您可以从 Test 中检索下一个值,并在插入之前将其分配给 ID。

于 2013-03-25T04:58:45.860 回答
0

听起来您想要更高的事务隔离级别或更严格的锁定

我不经常使用这些功能,所以如果我错了,希望有人会建议编辑,但你想要其中之一:

-- specify the strictest isolation level
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
insert into XYZ values((SELECT max(ID)+1 from XYZ),'Name') 

或者

-- make locks exclusive so other transactions cannot access the same rows
insert into XYZ values((SELECT max(ID)+1 from XYZ WITH (XLOCK)),'Name') 
于 2013-03-25T05:23:51.607 回答