2012-03-06 2 views
1

にC#の同期ロジックを以下の...私は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; 
} 

は私が書かれているストアドプロシージャているが、私は他に同じことをC#で正しく、非常に高速に実行タイムアウト、5秒に設定しているとして、それはタイムアウトがたくさんになり、唯一の問題は、ある私がする必要はありデータベースを複数のクライアントに提供するように、これをストアドプロシージャに移動します。

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私は思慮深いですか? トランザクションで実行していてもロックが必要ですか?

答えて

2

はい、あなたは思っています。 SQL Serverがロックを管理できるようにします。

create procedure [GetPageID] 
    @SpaceRequested int 
as 
begin 
    set nocount on; 

    begin tran; 

    update top (1) pages 
    set 
    SpaceAvailable -= @SpaceRequested, 
    SpaceOccupied += @SpaceRequested 
    output 
    inserted.PageID 
    where 
    SpaceAvailable > @SpaceRequested 
    order by PageID asc; 

    commit tran; 

end; 

以上も(場合には、あなたがそれを好むか、SQL Serverのバージョンが古すぎる)あなたは、あなたの質問に見せている二段階方式で書き込むことができます。

create procedure [GetPageID] 
    @SpaceRequested int 
as 
begin 
    set nocount on; 

    begin tran; 

    declare @page_id int; 

    select top (1) @page_id = PageID 
    from pages with (updlock, rowlock) 
    where SpaceAvailable > @SpaceRequested 
    order by PageID asc; 

    update Pages 
    set 
    SpaceAvailable = SpaceAvailable - @SpaceRequested, 
    SpaceOccupied = SpaceOccupied + @SpaceRequested 
    where 
    PageID = @page_id; 

    commit tran; 

    select @page_id; 

end; 
+0

あなたの答えをありがとう、なぜ私の現在のロジックを変更した、それは間違っていたと思いますか?私はSPの専門家ではないので、私は好奇心から尋ねるだけです。あなたは選択と更新の両方を1つのステートメントで行うように見えますか? –

+0

私はロジックを変更していない、私は実装を変更しました。あなたは多くの不必要なことをしている、これらは削除されました。唯一の選択は '@ res'テーブルからのものですが、update文は何も選択しませんが、ページIDを返します。これを書いたので、私は単に一時テーブルなしでクライアントに出力することができたことに気付きました。 – GSerg

+0

これはまた、TransactionScope内で同じロジックをカプセル化している場合、ストアドプロシージャが必要ないことを意味しますか? –

関連する問題