作者 www.itsvse.com @小渣渣 !
插入基础数据成功!
测试ConcurrencyCheck特性完成
更新成功!备注1
更新异常!备注2,异常信息!Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions.
测试Timestamp和ConcurrencyCheck区别
UpdateTab1更新成功!名字1
UpdateTab2更新成功!名字1
UpdateTab2更新异常!名字2,异常信息!Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions.
UpdateTab1更新成功!名字2
【TimeStamp】
TimeStamp特性可以应用到领域类中,只有一个字节数组的属性上面,这个特性,给列设定的是tiemStamp类型。在并发的检查中,Code-First会自动使用这个TimeStamp类型的字段。
【ConcurrencyCheck】
ConcurrencyCheck特性可以应用到领域类的属性中。当EF执行更新操作的时候,Code-First将列的值放在where条件语句中,你可以使用这个CurrencyCheck特性,使用已经存在的列做并发检查,而不是使用单独的TimeStamp列来做并发检查。
我们首先新建一个上下文对象,来演示Timestamp和ConcurrencyCheck在并发处理中的区别!
下面是上下文的代码:
我们看一下数据库的列,如下:
我们会发现,tab1和tab2都有Id、Name、Remark列,tab2比tab1多RowVersion列。
先附上测试代码:
【ConcurrencyCheck原理】
我们在Tab1的Remark属性上面加上了ConcurrencyCheck特性,
我们在同时更新同一条数据的Name属性值的时候,没有抛出异常!
生成sql语句:
exec sp_executesql N'UPDATE [dbo].[Tab1]
SET [Name] = @0
WHERE (([Id] = @1) AND ([Remark] = @2))
',N'@0 nvarchar(max) ,@1 int,@2 nvarchar(max) ',@0=N'名字1',@1=1,@2=N'备注1' exec sp_executesql N'UPDATE [dbo].[Tab1]
SET [Name] = @0
WHERE (([Id] = @1) AND ([Remark] = @2))
',N'@0 nvarchar(max) ,@1 int,@2 nvarchar(max) ',@0=N'名字2',@1=1,@2=N'备注1'
我们在同时更新同一条数据的Remark属性值的时候,抛出了异常!
生成sql语句:
exec sp_executesql N'UPDATE [dbo].[Tab1]
SET [Remark] = @0
WHERE (([Id] = @1) AND ([Remark] = @2))
',N'@0 nvarchar(max) ,@1 int,@2 nvarchar(max) ',@0=N'备注1',@1=1,@2=N'备注' exec sp_executesql N'UPDATE [dbo].[Tab1]
SET [Remark] = @0
WHERE (([Id] = @1) AND ([Remark] = @2))
',N'@0 nvarchar(max) ,@1 int,@2 nvarchar(max) ',@0=N'备注2',@1=1,@2=N'备注'
我们可以,发现,同时取同一条Id为1的数据,都取到了Remark属性的值,在更新Remark属性的时候,都用Remark作为更新条件,
第一条sql语句可以更新成功,然后把Remark改成了“备注1”,在执行更新第二条sql语句的时候,会更新失败,因为Remark的值已经改变。
【Timestamp原理】
我们Tab2添加了一个RowVersion的属性(名字可以随便取),并添加了Timestamp的特性!!!
我们在同时更新同一条数据的Name值的时候,第一条更新成功,第二条更新失败,并且抛出异常,我们来看一下生成的sql代码!
exec sp_executesql N'UPDATE [dbo].[Tab2]
SET [Name] = @0
WHERE ((([Id] = @1) AND ([RowVersion] = @2)) AND ([Remark] = @3))
SELECT [RowVersion]
FROM [dbo].[Tab2]
WHERE @@ROWCOUNT > 0 AND [Id] = @1',N'@0 nvarchar(max) ,@1 int,@2 binary(8),@3 nvarchar(max) ',@0=N'名字1',@1=1,@2=0x00000000000007D1,@3=N'备注' exec sp_executesql N'UPDATE [dbo].[Tab2]
SET [Name] = @0
WHERE ((([Id] = @1) AND ([RowVersion] = @2)) AND ([Remark] = @3))
SELECT [RowVersion]
FROM [dbo].[Tab2]
WHERE @@ROWCOUNT > 0 AND [Id] = @1',N'@0 nvarchar(max) ,@1 int,@2 binary(8),@3 nvarchar(max) ',@0=N'名字2',@1=1,@2=0x00000000000007D1,@3=N'备注'
在执行第二条sql语句的时候,因为,已经找不到where条件的数据,所以更新失败,抛出异常!!!
因为,第一条sql语句执行成功之后,RowVersion的值会发生改变,如下图:
RowsVersion就是timestamp
丢失更新的解决方法
丢失更新概念:当用户同时修改一行数据,他们先读取数据,放在前端进行修改,当修改后,再提交数据,这样最后提交的数据会覆盖先前提交的数据,这样就造成了丢失更新。
长话短说,介绍防止丢失更新的方法:
使用RowsVersion时间戳。
每次更新的时候,mssql都会自动的更新rowversion的值,若一行在读前与更新前的值前后不一致,就说明有其他的事务更新了此列,这样就可以不更新此列,从而防止了丢失更新的情况。
最后,附上源代码:
CodeFirstDemo.rar
(4.94 KB, 下载次数: 13)
|