使用TransactionScope不会重新设置标识列

时间:2011-06-06 21:23:59

标签: .net database unit-testing transactions

我已经开始使用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)

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

干杯。 雅各

2 个答案:

答案 0 :(得分:7)

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

这是设计使得在整个交易期间不必在柜台上放置专有锁定的身份。

答案 1 :(得分:2)

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

例如

  1. 您开始交易
  2. 您在表t中插入记录:标识字段设置为10
  3. John,在另一个并发客户端中插入表t中的记录。由于第一个事务尚未提交或回滚,因此对于John的事务
  4. ,标识字段设置为11
  5. John提交了他的交易。存储id = 11的记录
  6. 您回滚交易
  7. 您将身份重新设置为之前的值,即9
  8. 您插入2条新记录。第二个将具有id = 11,具有一致的身份碰撞
  9. 如果您的单元集成测试并行运行,这可能会发生(这是NCrunch的一种非常常见的行为)。

    经验法则:在回滚后不要重新设定

    另请参阅marc_sthis question的回复