假设,我即将开始使用ASP.NET和SQL Server 2005的项目。我必须为此应用程序设计并发需求。我打算在每个表格中添加一个TimeStamp列。在更新表格时,我将检查TimeStamp列是否与选定的相同。Sql transactrion的并发处理
这种方法是否足够?或者在任何情况下这种方法都有缺点吗?
请指教。
感谢
Lijo
假设,我即将开始使用ASP.NET和SQL Server 2005的项目。我必须为此应用程序设计并发需求。我打算在每个表格中添加一个TimeStamp列。在更新表格时,我将检查TimeStamp列是否与选定的相同。Sql transactrion的并发处理
这种方法是否足够?或者在任何情况下这种方法都有缺点吗?
请指教。
感谢
Lijo
的首先,你在你的问题描述的方式在我看来与MS SQL ASP.NET应用程序的数据库的最佳方式。数据库中没有锁定。它与永久断开连接的客户端类似于Web客户端是完美的。
如何从一些答案中读到,在术语中存在误解。我们都指使用Microsoft SQL Server 2008或更高版本来保存数据库。如果您在MS SQL Server 2008文档主题“rowversion(的Transact-SQL)”,在打开,你会发现以下几点:
“时间戳对于 rowversion数据类型的同义词,并受 数据类型同义词的行为。“...... ”的时间戳语法弃用。 此功能将在 未来版本的Microsoft SQL 服务器中删除。避免在 新的开发工作中使用该功能,并计划 修改当前使用 此功能的应用程序。”
所以时间戳数据类型为MS SQL的rowversion数据类型的同义词。它拥有64位,其在每个数据库内部存在并且可以被看作是@@ DBTS。一个行的数据库中的一个表的修改之后,计数器将被增加。
正如我读取计数器你的问题我读“时间戳”作为类型rowversion数据的列名。我个人更喜欢名字RowUpdateTimeStamp。在AzManDB中(请参阅以数据库为商店的Microsoft授权管理器),我可以看到这样的名称。有时也用于ChildUpdateTimeStamp跟踪分层RowUpdateTimeStamp结构(相对于触发)。
我实现了这个办法,我的最后一个项目,并很高兴。一般来说,你做以下:
SELECT s.Id AS Id
,s.Name AS SoftwareName
,m.Name AS ManufacturerName
,CASE WHEN s.RowUpdateTimeStamp > m.RowUpdateTimeStamp
THEN s.RowUpdateTimeStamp
ELSE m.RowUpdateTimeStamp
END AS RowUpdateTimeStamp
FROM dbo.Software AS s
INNER JOIN dbo.Manufacturer AS m ON s.Manufacturer_Id=m.Id
或进行数据铸像下面
SELECT s.Id AS Id
,s.Name AS SoftwareName
,m.Name AS ManufacturerName
,CASE WHEN s.RowUpdateTimeStamp > m.RowUpdateTimeStamp
THEN CAST(s.RowUpdateTimeStamp AS bigint)
ELSE CAST(m.RowUpdateTimeStamp AS bigint)
END AS RowUpdateTimeStamp
FROM dbo.Software AS s
INNER JOIN dbo.Manufacturer AS m ON s.Manufacturer_Id=m.Id
举行RowUpdateTimeStamp为BIGINT,其对应ULONG数据类型的C#。如果您从多个表中创建OUTER JOINT或JOINT,则所有表格中的构造MAX(RowUpdateTimeStamp)
将显得稍微复杂一些。因为MS SQL不支持像MAX(A,B,C,d,E)对应的构建函数可以看起来像以下:
(SELECT MAX(rv)
FROM (SELECT table1.RowUpdateTimeStamp AS rv
UNION ALL SELECT table2.RowUpdateTimeStamp
UNION ALL SELECT table3.RowUpdateTimeStamp
UNION ALL SELECT table4.RowUpdateTimeStamp
UNION ALL SELECT table5.RowUpdateTimeStamp) AS maxrv) AS RowUpdateTimeStamp
spSoftwareUpdate
存储过程可能看起来像CREATE PROCEDURE dbo.spSoftwareUpdate
@Id int,
@SoftwareName varchar(100),
@originalRowUpdateTimeStamp bigint, -- used for optimistic concurrency mechanism
@NewRowUpdateTimeStamp bigint OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
-- ExecuteNonQuery() returns -1, but it is not an error
-- one should test @NewRowUpdateTimeStamp for DBNull
SET NOCOUNT ON;
UPDATE dbo.Software
SET Name = @SoftwareName
WHERE Id = @Id AND RowUpdateTimeStamp <= @originalRowUpdateTimeStamp
SET @NewRowUpdateTimeStamp = (SELECT RowUpdateTimeStamp
FROM dbo.Software
WHERE (@@ROWCOUNT > 0) AND (Id = @Id));
END
dbo.spSoftwareDelete
存储过程的代码看起来像一样。如果您未打开NOCOUNT
,则可以生成DBConcurrencyException在情景中会自动生成很多。 Visual Studio为您提供了使用乐观并发的可能性,如TableAdapter
或DataAdapter
的高级选项中的“使用乐观并发”复选框。
如果你看看dbo.spSoftwareUpdate
存储过程carful你会发现,我使用RowUpdateTimeStamp <= @originalRowUpdateTimeStamp
在WHERE而不是RowUpdateTimeStamp = @originalRowUpdateTimeStamp
。我这样做是因为,具有客户端的@originalRowUpdateTimeStamp
的值通常是从多个表格构建为MAX(RowUpdateTimeStamp)
。所以它可以是RowUpdateTimeStamp < @originalRowUpdateTimeStamp
。要么你应该使用严格的相等性=并且在这里重现与您在SELECT语句中使用的相同的复杂JOIN语句,或者使用< =像我这样构建并保持与以前完全相同的安全性。
顺便说一下,基于RowUpdateTimeStamp,可以为数据创建非常好的价值ETag它可以在HTTP头与数据一起发送到客户端。通过使用ETag,您可以在客户端实施智能数据缓存。
我不能在这里写完整的代码,但你可以在互联网上找到很多例子。我只想重申,在我看来,使用乐观并发基于rowversion一次是在大多数的情况下ASP.NET的最佳途径。
我不知道是应该并发在这样的数据库进行处理。数据库本身应该能够管理隔离和事务行为,但是线程行为应该在代码中完成。
他没有提到穿线。数据库必须能够处理并发访问 - 无论这些来自单个多线程应用程序还是来自多个应用程序实例,或者两者都不在此处,也不在此处。 – 2010-04-17 13:21:39
然后,他需要关注自己的酸性和孤立性。 – duffymo 2010-04-17 14:06:49
在SQL Server中,针对某种情况的推荐方法是创建一个类型为'rowversion'的列,并使用它来检查该行中是否有任何字段已更改。
SQL Server保证如果行中的任何值发生更改(或插入新行),则rowversion列会自动更新为不同的值。让数据库为你处理这个比你自己做的更可靠。
在您的更新语句中,您只需添加一个where子句来检查rowversion值是否与您第一次检索该行时的值相同。如果不是这样,别人已经改变了行(即:它的肮脏)
而且,从该页面:
时间戳语法已被弃用。 此功能将在 未来版本的Microsoft SQL 服务器中删除。避免在 新开发工作中使用此功能,并计划到 修改当前使用 此功能的应用程序。
排版建议是正确的我会说,但它令人失望地看到时间戳将很快被弃用。我的一些旧应用程序因为不同的原因而使用它,然后检查并发性。
可能不是一个好主意 - 看看这篇文章http://www.mssqltips.com/tip.asp?tip=1501 – 2010-04-17 13:12:13
谢谢。它提供了一些亮点。一个问题 - 为什么我们说在悲观条件下使用锁定比时间戳更好?假设user1读取它并去了他的办公室,其他用户在得到错误信息之前必须等很长时间,对吧?如果我们使用时间戳方法,我们不能得到即时回复? 这里缺少的链接是什么? – Lijo 2010-04-17 13:38:44
“悲观条件”意味着锁定 - 这就是为什么很多人知道他们在做什么使用它 – 2010-04-17 13:43:29