У меня есть следующая логика Entity Framework, и я хочу перевести на хранимую процедуру, я пытался использовать эксклюзивную блокировку в хранимой процедуре, но это приводит к большому количеству таймаутов ...
Думайте о странице как о некотором родежесткого диска, который имеет 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
Я не очень разбираюсь в хранимых процедурах, но мне нужно размещать страницы в заблокированном режиме, чтобы ни одна страница не была переполнена.
Я ДУМАЮ? Даже если я работаю в транзакции, мне все еще нужна блокировка?