Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/256.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/86.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# SQL Server更新/选择密钥顺序_C#_Sql_Sql Server - Fatal编程技术网

C# SQL Server更新/选择密钥顺序

C# SQL Server更新/选择密钥顺序,c#,sql,sql-server,C#,Sql,Sql Server,我们有一个带有键字段的表,另一个表包含该键序列的当前值,即,要插入新记录,您需要: UPDATE seq SET key = key + 1 SELECT key FROM seq INSERT INTO table (id...) VALUES (@key...) 今天我一直在调查冲突,发现如果不使用事务,上述并行运行的代码会导致冲突,但是,交换更新和选择行不会导致冲突,即: SELECT key + 1 FROM seq UPDATE seq SET key = key + 1 INSER

我们有一个带有键字段的表,另一个表包含该键序列的当前值,即,要插入新记录,您需要:

UPDATE seq SET key = key + 1
SELECT key FROM seq
INSERT INTO table (id...) VALUES (@key...)
今天我一直在调查冲突,发现如果不使用事务,上述并行运行的代码会导致冲突,但是,交换更新和选择行不会导致冲突,即:

SELECT key + 1 FROM seq
UPDATE seq SET key = key + 1
INSERT INTO table (id...) VALUES (@key...)
有人能解释为什么吗?我对更好的方法不感兴趣,我将使用事务,我不能改变数据库设计,我只对为什么我们观察我们所做的事情感兴趣


我使用C的SqlConnection、SqlCommand和SqlDataAdapter将两行SQL作为单个字符串运行。

首先,您的查询没有完全意义。以下是我认为你实际上在做的事情:

UPDATE seq SET key = key + 1
SELECT @key = key FROM seq
INSERT INTO table (id...) VALUES (@key...)

您遇到了与事务隔离级别相关的并发问题

事务隔离级别代表了并发性需求(即性能)和数据质量需求(即准确性)之间的折衷

默认情况下,SQL使用读提交隔离级别,这意味着您不能对已被另一个事务修改但尚未提交到表的数据进行脏读。然而,这并不意味着您可以免于其他类型的并发问题

在您的情况下,您遇到的问题称为不可重复读取

在第一个示例中,第一行是读取键值,然后更新它。为了使更新将列设置为key+1,它必须首先读取key的值。然后第二行的SELECT将再次读取键值。在读提交或读未提交隔离级别中,另一个事务可能同时完成对键字段的更新,这意味着第2行将把它读取为键+2,而不是预期的键+1

现在,在第二个示例中,一旦键值被读取、修改并放入@key变量中,就不会再读取它了。这可以防止不可重复读取的问题,但您仍然不能完全避免并发问题。在这种情况下可能发生的是丢失的更新,在这种情况下,两个或多个事务最终尝试将键更新为相同的值,然后向表插入重复的键

要绝对确定此结构没有设计的并发问题,您需要使用锁定提示来确保对密钥的所有读取和更新都是可序列化的,即不并发的。这将有可怕的性能,但有了UPDLOCK,HOLDLOCK会让你达到目的


如果您无法更改数据库设计,那么最好的解决方案是找到能够更改的人。正如Brian Hoover所指出的,一个自动递增的标识列是实现这一点的最佳方法。您现在的操作方式将SQL的V-8引擎简化为只允许在一个气缸上启动的引擎。

为什么不使用自动增量?SQL Server将其保存在缓冲区中,因此不会发生冲突。@key在哪里被赋值?@BrianHoover正如我在问题中所说的,我不能更改数据库设计。@BZN_DBer这不是我使用的实际代码,只是一种表示。我理解,但你问的是冲突的细节,我认为在这种情况下,准确的实施是很重要的。谢谢。如果执行插入操作,然后选择@@IDENTITY,则始终会返回正确的值吗?那里没有竞争条件?是和否。实际上有3种方法可以获取标识值-IDENT_CURRENT、@@identity和SCOPE_identity-每种方法都适用于不同的情况。这不是比赛条件的问题,而是范围的问题。我建议您研究Microsoft的示例代码,比较以下三种代码:
SELECT @key = key + 1 FROM seq
UPDATE seq SET key = @key
INSERT INTO table (id...) VALUES (@key...)