使用 TransactionScope 不会重新种子标识列

发布于 2024-11-13 23:02:26 字数 962 浏览 2 评论 0原文

我已开始使用 TransactionScope 来帮助我的设备测试,以便将我的测试数据库恢复到之前的状态。将其与 SpecFlow 一起使用,我有一个如下所示的基类:

public class TransactionScopedFeature
{
    private TransactionScope Scope { get; set; }

    [BeforeScenario]
    public void BaseSetup()
    {
        this.Scope = new TransactionScope(TransactionScopeOption.RequiresNew);
    }

    [AfterScenario]
    public void BaseCleanup()
    {
        if (this.Scope != null)
        {
            this.Scope.Dispose();
        }
    }
}

上述所有工作都有效,因为当我将记录添加到数据库时,当我在测试完成后查询表时,这些表是空的。很棒的东西,而且确实非常聪明!

我的问题与这些表中的标识列有关。我注意到,当我多次运行测试时,测试表的 ID 列增加 1。我假设由于 TransactionScope 会回滚更改,因此身份种子也会回滚。

我的这个假设是错误的吗——数据库就是这样工作的吗?如果是这种情况,我还可以在执行此操作的每个场景之前运行一个 SQL 脚本:

DBCC CHECKIDENT ('dbo.Items', reseed, 0)

我只是想检查一下,以防万一做错了什么,或者这是正常的数据库行为。

干杯。 贾斯。

I've started using TransactionScope to help with my unit tests, in order to put my test database back to it's previous state. Using this with SpecFlow, I have a base class like so:

public class TransactionScopedFeature
{
    private TransactionScope Scope { get; set; }

    [BeforeScenario]
    public void BaseSetup()
    {
        this.Scope = new TransactionScope(TransactionScopeOption.RequiresNew);
    }

    [AfterScenario]
    public void BaseCleanup()
    {
        if (this.Scope != null)
        {
            this.Scope.Dispose();
        }
    }
}

All of the above works, in that when I add records to the database, when I then query the tables after the tests have finished, those tables are empty. Great stuff, and very clever indeed!

My question relates to identity columns in these tables. What I've noticed is that, when I run my tests numerous times, the ID column of my test table increases by 1. I assumed that since the TransactionScope would rollback the changes, that the identity seed would also be rolled back.

Am I wrong in making this assumption - is this just how databases work? If that is the case, I could also run a SQL script before each of my scenarios that does this:

DBCC CHECKIDENT ('dbo.Items', reseed, 0)

I just wanted to check in case I was doing something wrong, or this is normal database behaviour.

Cheers.
Jas.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

少女七分熟 2024-11-20 23:02:26

标识列的种子值不会随 SQL Server 中事务的其余部分一起回滚。

这是设计使然,以便在整个事务持续时间内不必在计数器上放置独占锁以获取身份。

The seed value for an identity column does not get rolled back with the rest of a transaction in SQL Server.

This is by design so that an exclusive lock does not have to be placed on the counter for the identity for the entire duration of the transaction.

辞旧 2024-11-20 23:02:26

回滚后重新播种身份可能非常危险:如果另一个事务插入记录,就会发生身份冲突。

例如

  1. 你启动一个事务
  2. 你在表t中插入一条记录:identity字段设置为10
  3. John,在另一个并发客户端在表t中插入一条记录。由于第一个事务尚未提交或回滚,因此 John 的事务的标识字段设置为 11
  4. John 提交了他的事务。存储 id = 11 的记录
  5. 您回滚事务
  6. 您将身份重新设置为之前的值,即 9
  7. 您插入 2 条新记录。第二个的 id = 11,会发生身份冲突。

这种情况尤其可能发生在您的 unit 集成测试并行运行时(这是 NCrunch 中非常常见的行为)。

经验法则:回滚后不要重新播种

另外,请参阅 marc_s这个问题

Reseeding the identity after a rollback can be very dangerous: should another transaction insert a record, an identity collision would happen.

For example

  1. You start a transaction
  2. You insert a record in table t: the identity field is set to 10
  3. John, in another concurrent client insert a record in table t. Since the first transaction has not committed nor rollback, the identity field is set to 11 for John's transaction
  4. John commits his transaction. A record with id = 11 is stored
  5. You rollback your transaction
  6. You reseed the identity to the previous value, that is 9
  7. You insert 2 new records. The second one will have the id = 11, with a consiquent identity collision

This may happen especially if your unit integration tests run in parallel (this is a very common behavior with NCrunch).

Rule of thumb: don't reseed after a rollback

Also, see the reply marc_s gave to this question

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文