T-SQL并发问题:拍卖/竞标系统

我目前正在使用ASP.NET 3.5和sqlServer 2008开发在线拍卖系统.我已经达到了开发的地步,我需要确保我的系统能够合理地处理在以下情况下可能出现的并发问题:

两个人 – 杰拉尔丁和约翰 – 想要竞标目前价格为50英镑的拍卖品. Geraldine以55英镑的价格出价,约翰出价52英镑.系统现在有两个页面’submit_bid.aspx’正在运行;该页面的每个副本都会检查他们的出价是否足够高,他们都看到了,并且他们提交了出价.如果约翰的出价首先出现,那么拍卖品的价格目前是55英镑,过了一会儿,它被52英镑的出价所取代.

我需要做的是锁定拍卖项目行,直到当前的出价价格更新,然后允许任何其他出价者检查当前出价并投标.

我的问题是:使用T-sql和/或ADO.NET这样做的最佳实践方法是什么?

我目前有一个AuctionItem表,其中包含以下字段(以及我为简洁起见未包含的其他字段):

AuctionItemID   INT
CurrentBidPrice MONEY
CurrentBidderID INT

我已经进行了一些研究,并提出了以下T-sql(伪代码):

@Bid MONEY
@AuctionItemID INT

BEGIN TRANSACTION

SELECT @CurrentBidPrice = CurrentBidPrice
FROM AuctionItem
WITH (HOLDLOCK,ROWLOCK)
WHERE AuctionItemID = @AuctionItemID

/* Do checking for end of Auction,etc. */

if (@Bid > @CurrentBidPrice)
BEGIN
  UPDATE AuctionItem
  SET CurrentBidPrice = @Bid
  WHERE AuctionItemID = @AuctionItemID
END

COMMIT TRANSACTION

我还读过,如果我包含SET LOCK_TIMEOUT,我还可以减少失败的并发更新次数.例如:

SET LOCK_TIMEOUT 1000

…将使并发更新等待1000毫秒以释放锁.这是最佳做法吗?

解决方法

资料来源:“chrisrlong”,http://www.dbasupport.com/forums/archive/index.php/t-7282.html

以下是用于处理多用户并发问题的方法

>什么都不做(不受欢迎)

>用户1读取记录
>用户2读取相同的记录
>用户1更新该记录
>用户2更新相同的记录

用户2现在已经覆盖了用户1所做的更改.它们完全消失了,好像它们从未发生过一样.这称为“丢失更新”.
>悲观锁定(读取时锁定记录.)

>用户1读取记录并通过在记录上放置一个独占锁来锁定它(FOR UPDATE子句)
>用户2尝试读取并锁定相同的记录,但现在必须在用户1后面等待
>用户1更新记录(当然,提交)
>用户2现在可以使用用户1所做的更改来读取记录
>用户2使用用户1的更改更新记录

丢失的更新问题已解决.这种方法的问题是并发性.用户1正在锁定他们可能永远不会更新的记录.用户2甚至无法读取记录,因为他们在阅读时也想要独占锁定.这种方法需要太多的独占锁定,并且锁的使用时间太长(通常跨越用户控制 – 绝对禁止).这种方法几乎从未实现过.
>使用乐观锁定.
乐观锁定在阅读时不使用排他锁.相反,在更新期间进行检查以确保记录在读取后未被更改.通常,这是通过添加版本/ etc列(INT / numeric,保存在生成​​UPDATE语句时增加的数值)来完成的. IE:

UPDATE YOUR_TABLE
   SET bid = 52
 WHERE id = 10
   AND version = 6

另一种选择是使用时间戳,而不是数字列.除了实现乐观并发之外,此列仅用于其他目的.它可以是数字或日期.想法是在插入行时给出一个值.每当读取记录时,也会读取timestamp列.执行更新时,将检查时间戳列.如果它在UPDATE时具有与读取时相同的值,则一切正常,执行UPDATE并更改时间戳!如果时间戳值在UPDATE时间不同,则会向用户返回错误 – 他们必须重新读取记录,重新进行更改,并尝试再次更新记录.

>用户1读取记录,包括21的时间戳
>用户2读取记录,包括21的时间戳
>用户1尝试更新记录. had(21)中的时间戳与数据库(21)中的时间戳匹配,因此执行更新并更新时间戳(22).
>用户2尝试更新记录.手中的时间戳(21)与数据库(22)中的时间戳不匹配,因此返回错误.用户2现在必须重新读取记录,包括新的时间戳(22)和用户1的更改,重新应用其更改并重新尝试更新.

对照

>乐观锁定与数据库无关 – 无需隔离级别和隔离级别的数据库特定语法.>我在时间戳上使用数字列 – 更少的数据&麻烦管理

相关文章

SELECT a.*,b.dp_name,c.pa_name,fm_name=(CASE WHEN a.fm_n...
if not exists(select name from syscolumns where name=&am...
select a.*,pano=a.pa_no,b.pa_name,f.dp_name,e.fw_state_n...
要在 SQL Server 2019 中设置定时自动重启,可以使用 Window...
您收到的错误消息表明数据库 'EastRiver' 的...
首先我需要查询出需要使用SQL Server Profiler跟踪的数据库标...