【问题标题】:Are Transactions Always Atomic?事务总是原子的吗?
【发布时间】:2011-07-12 07:43:15
【问题描述】:

我试图更好地理解 SQL Server 事务的细微差别。

假设我有一个更新 1,000 条现有行的查询,将其中一列更新为从 1 到 1,000 的值。可以执行此查询,并且在完成后,这些行不会按顺序编号。这是因为在我的查询完成之前,另一个查询可能会修改这些行之一。

另一方面,如果我将这些更新包装在一个事务中,这保证了如果任何一个更新失败,我可以使所有更新失败。但这是否也意味着当我完成后这些行将保证是连续的?

换句话说,事务总是原子的吗?

【问题讨论】:

  • 你为什么要它们连续?
  • 既然这是我对原子定义的理解,是的,事务将永远是原子的(IOW - 要么全部成功,要么不更新)

标签: sql sql-server transactions


【解决方案1】:

但这是否也意味着当我完成后这些行将被保证是连续的?

没有。这与事务无关,因为您所要求的根本不存在:关系表没有顺序,要求“顺序行”是错误的问题。您可以将问题改写为“1000 条更新的行是否包含从 1 到 1000 的整个序列,没有间隙”?很可能是的,但事实是,根据您进行更新的方式,可能存在差距。这些差距不会出现,因为更新的行在提交之前的更新之后被修改,而是因为更新将是无操作(不会更新任何行),这是读-修改-写回更新类型的常见问题(由于并发操作,读取和回写之间的行“消失”)。

要更准确地回答您的问题,您的代码是否正确,您必须发布用于更新的确切代码,以及准确的表结构,包括所有索引。

【讨论】:

  • 当我谈论行是否有序时,我指的是我正在编写的顺序值,而不是行的物理顺序。换句话说,如果没有其他人正在访问数据库,那么我就可以保证有顺序值。问题是在我更新期间是否有其他人来修改一个或多个行。
  • 您的更新不是即时的。无论您如何操作,这 1000 个更新都将在时间线上“传播”。在任何写入(插入、删除、更新)之前,SQL Server 将使用排他锁锁定正在修改的行。在事务提交(或回滚)之前始终保持此排他锁,并防止任何其他事务修改该行。但是,正如我所说,这并不一定保证结果将是 1000 个连续值。
  • 关于锁的一些细节:锁可以升级为页/分区/表排他锁,锁可以应用于行的键而不是行本身和其他更精细的点。我们现在不应该进入这些细节,我上面的解释应该基本上涵盖了你的情况。
【解决方案2】:

原子表示事务中的操作要么发生,要么不发生。

如果 1,000 条语句中的一条失败,则事务中的 操作将提交。事务中的语句样本越小——比如 100——意味着导致错误的 100 个块(比如在第 501 个)可以提交(前 400 个;500 个块不会,600 个+ 块会)。

但这是否也意味着当我完成后这些行将保证是连续的?

您必须提供更多关于您在事务中所做的事情的上下文才能“顺序”。

【讨论】:

  • 我怀疑他在问,如果他的更新提交是他保证行将是连续的(即它们被其他进程锁定,直到它们全部完成)
  • 好吧,那么也许原子是错误的词。我试图确定在我提交事务时是否保证没有其他人会修改任何受影响的行。至于如何我使它们连续,这并不重要。如果有帮助,一种方法是遍历 1,000 个 UPDATE 查询。
  • @JNK:是的,这正是我要问的。
  • @Jonathan Wood:您想要的功能称为“锁定”。您可以悲观地使用 table/etc 锁定,也可以乐观地使用列来允许第一次更新发生。
  • @Leslie:不,滚动你自己的自动增量不如使用数据库替代品安全(谢天谢地,序列现在是 ANSI 并且 SQL Server 在下一个版本中支持它们)
【解决方案3】:

这两点不相关

顺序

如果您插入 1 到 1000 的值,它将与 WHERE 和 ORDER BY 连续,以将您限制为某些列中的这 1000 行。除非有重复,否则你需要一个唯一的约束

如果您依赖 IDENTITY,则无法保证:Do Inserted Records Always Receive Contiguous Identity Values

原子性

所有事务都是原子的:

【讨论】:

  • 您可能是对的,但您的第一点似乎与我所说的无关。假设我不是存储顺序值,而是将相同的值写入 1,000 行中的列。完成后,这些行在更新的列中是否包含相同的值?好吧,如果另一个用户在我的操作过程中写入其中一个行,则不会。那么,如果我将相同的值作为事务的一部分写入 1000 行呢?
  • 所有 1000 行都被专门锁定以供您写入:在您完成或回滚之前,其他人无法更改它们。这是 ACID 中的隔离。在您的示例中,这取决于谁先到达那里。你们中的一个会覆盖另一个,但你的单独更新既是原子的又是排他的。对于超过 1000 行的表,不同的进程可以更新不同的行(除非更改锁粒度或隔离级别以防止这种情况发生,例如表锁:超出范围虽然在这里,因为这不是默认行为)
  • 为了清楚起见,我没有明确地创建一个锁。你的意思是交易的结果,对吗?如果是这样,看起来我的问题的答案包括“是”、“否”和“也许”。:-)
  • 更新暗示的 txn,是的。所有 dml 都使用锁(选择可以更改为脏读(此处超出范围)
【解决方案4】:

SQL 事务与所有数据库平台上的事务一样,将数据隔离以覆盖整个 ACID 首字母缩写词(原子、一致、隔离和持久)。所以答案是肯定的。

【讨论】:

    【解决方案5】:

    事务保证原子性。这就是我想说的。

    你的问题是,在你插入之后,它们只是“顺序的”,直到下一个事情出现并触及新记录之一。

    如果您流程中的另一个步骤要求它们仍然是连续的,那么该步骤也需要在您的原始事务中。

    【讨论】:

    • 我在问他们在事务提交的那一刻是连续的。是的,很明显,以后有人可能会出现并更改它们。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-09
    • 1970-01-01
    • 2019-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多