13

换句话说,是否保证以下“游标”方法有效:

  1. 从数据库中检索行
  2. 从返回的记录中保存最大的 ID 以供以后使用,例如LastMax
  3. 之后,"SELECT * FROM MyTable WHERE Id > {0}", LastMax

为了使它起作用,我必须确保我在步骤 1 中没有得到的每一行的 Id 都大于LastMax. 这是有保证的,还是我会遇到奇怪的比赛条件?

4

5 回答 5

20

保证绝对在任何情况下都不会获得可能小于或等于当前最大值的值?不,没有这样的保证。也就是说,这种情况可能发生的情况是有限的:

  1. 有人禁用身份插入并插入一个值。
  2. 有人重新设定身份列。
  3. 有人改变了增量值的符号(即不是+1而是改为-1)

假设没有这些情况,您可以避免竞争条件造成下一个值低于现有值的情况。也就是说,不能保证行将按照其标识值的顺序提交。例如:

  1. 打开一个事务,使用标识列插入到您的表中。假设它的值是 42。
  2. 将另一个值插入并提交到同一个表中。假设它的值为 43。

在提交第一个事务之前,43 存在但 42 不存在。身份列只是保留一个值,而不是规定提交的顺序。

于 2010-05-13T17:51:18.120 回答
4

我认为这可能会出错,具体取决于交易的持续时间考虑以下事件序列:

  1. 事务 A 开始
  2. 事务 A 执行插入 - 这会在标识列中创建一个新条目
  3. 事务 B 开始
  4. 事务 B 执行插入 - 这会在标识列中创建一个新条目
  5. 事务 B 提交
  6. 您的代码执行其选择并查看第二笔交易的身份值
  7. 事务 A 提交 -

您的代码永远不会找到事务 A 插入的行。执行第 6 步时,它尚未提交。并且在执行下一个查询时将找不到它,因为它在标识列中的值低于查询正在查找的值。

如果您使用未提交的隔离模式执行查询,它可能会起作用

于 2010-05-13T18:34:35.243 回答
2

身份将始终遵循定义身份的增量:

身份[(种子,增量)] http://msdn.microsoft.com/en-us/library/aa933196(SQL.80).aspx

可以是正数或负数(您可以让它向前或向后递增)。如果您将身份设置为向前递增,您的身份值将始终大于以前的值,但如果您回滚 INSERT,您可能会错过一些。

是的,如果您将身份增量设置为正值,您的循环逻辑将起作用。

于 2010-05-13T17:40:56.107 回答
1

唯一可能插入的记录是您不会得到的,如果有人打开身份插入并手动将记录插入跳过的 id(或在某些情况下插入负数)。这是一种相当罕见的情况,通常只能由系统管理员完成。例如,可能会重新插入意外删除的记录。

于 2010-05-13T17:40:49.747 回答
0

SQL Server 唯一保证的是您的 IDENTITY 列将始终递增。

不过要考虑的事情:

  1. 如果 INSERT 失败,IDENTITY 列无论如何都会增加;
  2. 如果发生回滚,IDENTITY 列将不会返回到之前的值;

这就解释了为什么 SQL Server 不保证顺序 INDENTITY。

有一种方法可以使用DBCC命令重置 IDENTITY 列。但在此之前,请考虑以下事项:

  1. 确保您的 IDENTITY 列没有被任何其他表引用,因为您的外键不能用它更新,所以前面的麻烦很大;
  2. 您可以使用SET IDENTITY_INSERT ON/OFF指令,以便您可以在插入行时手动指定 IDENTITY(以后不要忘记打开它)。

IDENTITY 列是 DBRM 中永远不会更改的最重要元素之一。

这是一个可以帮助您的链接:了解 IDENTITY 列

编辑: 您似乎所做的工作将作为 LastMax 的 IDENTITY 列将始终为每个 INSERTed 行递增。所以:

  1. 从数据表中选择行;
  2. 保存 LastMax 状态;
  3. 选择 Id > LastMax 的行。

3) 将只选择 IDENTITY 列将大于 LastMax 的行,因此在保存 LastMax 后插入。

于 2010-05-13T17:55:18.547 回答