2016-11-08 4 views
1

ムービーでのチケットの予約を考えてください。 x個のオープンシートがあります。あなたがサイトに来ると、ある期間座席の1つを予約したいと思います。シアターシートの予約

私はプライベート内部APIとパブリックAPIを持っています。パブリックAPIは、内部APIを呼び出し、そのシートを「予約中」ステータスにすることによって、座席予約を求めるアプリケーションに応答します。

私の問題は、同じ席を予約している人が2人いることがあり、その結果、1人がすべての情報を入力してから登録を完了できなくなるということです。

私はコードのスレッドを安全にしようとしましたが、同じシートの奇妙な重複割り当てがまだ残っています。

私は、次のような私の「予約」方式から、私のステータス更新を呼び出しています:

VisitStatusChangeResult visit_status_change_result = await ReserveSlotByLockedStatusUpdate(first_empty_seat);

これで私はSemaphoreSlimを使用してにスレッドsafteyを追加しようとしているステータス更新方法:

private static SemaphoreSlim m_ReserveOnlineSlotStatusUpdateSemaphore = new SemaphoreSlim(initialCount: 1, maxCount: 1); 


private async Task<VisitStatusChangeResult> ReserveSlotByLockedStatusUpdate(VisitQueryResult first_empty_seat) 
{ 
    await m_ReserveOnlineSlotStatusUpdateSemaphore.WaitAsync(); 

    try 
    { 
    return await ChangeStatus(new VisitStatusUpdateModel 
    { 
     VisitID = first_empty_seat.ID, 
     CurrentVisitStatusID = first_empty_online_visit.VisitStatusID, 
     NewVisitStatusID = (int)VisitStatuses.BeingBooked 
    }); 
    } 
    finally 
    { 
    m_ReserveOnlineSlotStatusUpdateSemaphore.Release(); 
    } 

} 

SemaphoreSlimを使用していても、2人で同じ席を掴むことができます。

+3

予約情報をデータベースに保存していますか?はいの場合、そのような状況が発生するのはなぜ(データベースレベルで)許可されていますか? – Evk

+0

はい、「BeingBooked」に設定されているものである 'VisitStatusID'のfkを持つデータベース内の行は、それぞれ1つの行です。クライアントが座席を予約するか、予約アプリケーションを終了するか、時間がなくなる。 – Mark

答えて

1

まず、メモリ内のロックを使用してデータベースリソースへの並列アクセスを保護することは、あまり良い考えではありません。すべてのデータベースには、それ専用のツールがあります。ほとんどの場合、あなたは、おおよそ次のように、この場合には楽観的同時実行を使用する必要がありますので、この席はまだ空いていないことが起こった場合

update Visit set VisitStatusID = BeingBooked, ClientID = CurrentClientID where VisitStatusID = Free 

だからあなたは、または今この席をご予約され を知って、そして - これは、文は0を返します(0行が変更されます)。これをチェックし、それに応じて行動する必要があります(この座席がすでに利用されていることをクライアントに通知し、座席をリフレッシュする)。

第2に、ロックは効果がありません。 2人のクライアントがReserveSlotByLockedStatusUpdateを順番にと呼んでいるのを防ぎますが、上記のようにオプティミスティックな並行性を実装していない限り、両方が同じ座席を予約するため、問題になります。

+0

お返事ありがとうございました。私たちは、更新する前に状態を更新する次の試みのために座席の状態をチェックしますが、これはまだ失敗する可能性がありますか?それが私たちがmysqlを使用している場合に役立ちます。 – Mark

+0

はい、チェックと更新の間に、行がすでに更新されている可能性があります(問題の行でデータベースの行ロックを取るなどしない限り)。しかし、あなたが定期的にセレクトをして、それをアップデートすれば、それは安全ではありません。 – Evk

+0

だから、この外部アクセス(DB)のために私はDBのconcurency方法論を介してこれを処理する必要があります。私がDBに当たっていなかったら、私が試したようなスレッドセーフな操作の中にとどまることができましたか? – Mark