如果我有一个具有多个CRUD操作的事务,Sql服务器如何/何时更新记录时间戳值

时间:2014-05-30 23:31:33

标签: entity-framework sql-server-2008-r2 entity-framework-5 asp.net-mvc-5

我正在开发一个asp.net mvc Web应用程序,我正在使用实体框架将我的表映射到模型类。 我有代表VMS的模型类: -

public partial class TMSVirtualMachine
    {
        public int TMSVirtualMachineID { get; set; }
        public int ServerID { get; set; }
        public int RoleID { get; set; }
        public Nullable<int> BackUpStatusID { get; set; }
        public Nullable<int> StatusID { get; set; }
        public Nullable<int> MonitoreID { get; set; }
        public Nullable<decimal> TotalStorage { get; set; }
        public string Comment { get; set; }
        public byte[] timestamp { get; set; }
        public Nullable<long> IT360SiteID { get; set; }

        public virtual TMSServer TMSServer { get; set; }
//cde goes here…
    }

我有以下存储库方法,它将所有当前服务器; s VMS移动到另一台服务器,通过更改VM的ServerID如下: -

public int changeVMsServer(AssignVMsToServer s, string username)
        {
            int count = 0;

var currentvms = tms.TMSVirtualMachines.Where(a => a.ServerID == s.serverIDForm);
            foreach (var v in currentvms)
            {
 v.ServerID = s.serverIDTo;
tms.Entry(v).State = EntityState.Modified;
count++;

}
SaveChanges();

            return count;
 }

目前,如果两个用户同时调用上述方法,其中一个将获得DBUpdateConcurrentException,因为VM尝试保存时的时间戳将与检索VM时的时间戳不同。 我的问题基本上是SQL Server 2008 r2如何管理时间戳列。让我们采取以下方案: -

  • 第一个用户检索5个虚拟机,然后生成5个SQL更新命令并保存。

  • 第二个用户检索5个VM,然后生成5个SQL更新,当尝试保存时,EF将检测到至少一个VM的时间戳已更改并引发DBUPdateException。

现在,当第一个用户执行5个SQL更新操作时,他的工作将不会保存,直到5个更新操作成功,因为5个更新操作包含在单个转换中。

Q1)那么什么时候sql server 2008 r2会更改5个服务器的timestamp列,当事务完成?,或者保存单个更新操作?,如果事务失败,sql server会返回旧的时间戳价值?

很抱歉这封长电子邮件,但我尝试寻找一个明确的答案,但无法得出最终结论。

1 个答案:

答案 0 :(得分:1)

MSDN documentation on timestamp非常明确:

  

是一种在数据库中公开自动生成的唯一二进制数的数据类型。 timestamp通常用作对表行进行版本标记的机制。存储大小为8个字节。时间戳数据类型只是一个递增的数字,不保留日期或时间。要记录日期或时间,请使用日期时间数据类型。

...

  

您可以使用行的timestamp列轻松确定自上次读取行以来该行中的任何值是否已更改。如果对该行进行了任何更改,则更新时间戳值。

因此,很明显,当行更改时,时间戳会被修改。

EF will use this column for concurrency checking:如果应用程序读取一行,修改它并尝试保存数据库中的更改以及自读取以来更改的时间戳,则抛出并发异常。

关于交易,您缺少的是“transaction isolation”概念。对行进行更改时,时间戳列会更改。但是如果不同的连接尝试读取此行会发生什么情况取决于隔离级别:行可以被锁定直到事务完成(因此另一个连接必须等到那一刻),或者另一个连接可以读取新的未注册的值或它可以读取旧值。这取决于隔离级别。

默认情况下,SQL Server中的隔离级别为:

  

READ COMMITTED   指定语句无法读取已修改但未由其他事务提交的数据。这可以防止脏读。数据可以由当前事务中的各个语句之间的其他事务更改,从而导致不可重复的读取或幻像数据。此选项是SQL Server的默认选项。