1
我有以下实体框架的逻辑,我想转换为存储过程,我一直在使用存储过程中的排它锁尝试,但它会导致很多超时的...翻译下面的C#同步逻辑存储过程
页面视为某种其中有4列
Pages
PageID
SpaceAvailable
SpaceOccupied
TotalSpace
硬盘的,我需要分配在网页我的对象的可用空间,如果对象不适合,它会得到下一个可用的页面。
// a static lock to prevent race condition
static object Locker = new Object();
long AllocateNewPage(MyContext context, int requestedSize){
long pageID = 0;
// what is T-SQL lock equaivalent?
lock(Locker){
using(TransactionScope scope = new TransactionScope()){
var page = context.Pages
.Where(x=>x.SpaceAvailable>requestedSize)
.OrderBy(x=>x.PageID)
.First();
page.SpaceOccupied = page.SpaceOccupied + requestedSize;
page.SpaceAvailable = page.SpaceAvailable - requestedSize;
context.SaveChanges();
scope.Commit();
pageID = page.PageID;
}
}
return pageID;
}
以下是存储过程我已经写了,但它会导致大量的超时,因为我已经设置在5秒超时,别的地方同样的事情正确,在C#中比较快的运行,唯一的问题是,我有将其移至存储过程,因为数据库现在将为多个客户端提供服务。
CREATE procedure [GetPageID]
(
@SpaceRequested int
)
AS
BEGIN
DECLARE @DBID int
DECLARE @lock int
DECLARE @LockName varchar(20)
SET @LockName = 'PageLock'
BEGIN TRANSACTION
-- acquire a lock
EXEC @lock = sp_getapplock
@Resource = @LockName,
@LockMode = 'Exclusive',
@LockTimeout = 5000
IF @lock<>0 BEGIN
ROLLBACK TRANSACTION
SET @DBID = -1
SELECT @DBID
return 0
END
SET @DBID = coalesce((SELECT TOP 1 PageID
FROM Pages
WHERE SpaceAvailable > @SpaceRequested
ORDER BY PageID ASC),0)
UPDATE Pages SET
SpaceAvailable = SpaceAvailable - @SpaceRequested,
SpaceOccupied = SpaceOccupied + @SpaceRequested
WHERE PageID = @DBID
EXEC @lock = sp_releaseapplock @Resource = @LockName
COMMIT TRANSACTION
SELECT @DBID
END
我对存储过程不太了解,但我需要在锁定模式下分配页面,以便不会填充页面。
AM我在想什么? 即使我在交易中运行,我还需要锁定吗?
感谢您的回答,但为什么您修改了我当前的逻辑,您认为这是错误的?我不是SP的专家,所以我只是出于好奇而问,看起来你在做一个语句的选择和更新? – 2012-03-06 15:49:56
我没有修改逻辑,我修改了实现。你正在做很多不必要的事情,这些都被删除了。唯一的选择来自'@ res'表,更新语句不会选择任何内容,尽管它返回页面ID。现在我写了这个,我意识到我可以简单地输出到没有临时表的客户端。 – GSerg 2012-03-06 15:53:18
这是否也意味着我不需要存储过程,如果我在TransactionScope中封装相同的逻辑? – 2012-03-07 08:44:23