0

私は次の問題を抱えています:

私たちのシステムには、リリースされたときにX回だけ購入できる製品があります。購入時に、中央購入アルゴリズムが存在する注文の数をチェックし、X未満の場合は購入を続行します。

疑似的なC#コードの場合:

public class OrderMethods
{

    public static Purchase(Product product, Client client)
    {

        int purchases = /* count order records of this product */;

        if(purchases>=MAX_ORDERS) throw PurchaseException();

        /* perform purchase by inserting order record in database */

     }

}

問題は、特定の製品に対する需要が高い場合、同時に多くの要求が発生し、MAX_ORDERSを超えるものが登録されることがあるということです。これは約1年に1回発生します:(。

これを解決するための最良の解決策は何ですか?ASP.NET/C#、Ling2SQL、MSSQLを使用しています。1日あたり1000件以上の注文があります。注文は、要求された順序で処理されることが重要です。

私がこれまでに思いついた解決策:

  • 1つのグローバルミューテックス?

  • 次のようなアクセス関数を使用して、ハッシュテーブルに格納された製品ごとに1つのミューテックス。

    private Mutex GetPurchaseMutex(Guid productId)
    {
    
    if (mutexTbl[productId] == null)
        {
            mutexTbl[productId] = new Mutex();
        }
        return (Mutex)mutexTbl[productId];
    }
    

ここで、mutexTblはハッシュテーブルです。ただし、ここでは、古いミューテックスを適切な方法で破棄する方法がわかりません。

  • OrderテーブルでT-SQLINSERTトリガーを使用して、注文の数を確認します。

    CREATE TRIGGER Triggers_OrderInsertTrigger ON Orders AFTER INSERT AS IF/*注文数が多いかどうかを確認します*/BEGIN RAISERROR('Too manyorders'、16、1); ロールバックトランザクション; リターンエンド;

しかし、私はこれらの解決策のどちらもあまり好きではありません。これをどのように解決しますか?

4

3 に答える 3

4

トランザクションで保護できる場合は、このロジックをデータベースレイヤーに移動すると思います。

発注されたオファーの数を確認し、問題がない場合は同じトランザクション内で新しい注文を行います。この間、新しいリクエストのトランザクション(発注数のクエリ)は、最初のリクエストが完了するまで停止されます。

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

BEGIN TRANSACTION

DECLARE @OrderCount int
SELECT @OrderCount = COUNT (ID) FROM [Order] WHERE ProductID = '234323'

IF (@OrderCount < @Threshold)
BEGIN
    INSERT INTO [Order] (ID, ProductID, ...)
    VALUES (NEWID(), '234323', ...)

    COMMIT TRANSACTION
    RETURN 0
END
ELSE
    ROLLBACK TRANSACTION
    RETURN 1
END
于 2010-04-27T11:55:19.287 に答える
3

この問題は、ここで説明した「未発送の注文が2つしかない」問題とよく似ています。(警告、記事はかなり長いですが、非常に有益です)。しかし、私はあなたのオプションは基本的に次のとおりだと思います:

  • その完全なビジネスロジック(検証を含む)をデータベースに配置します(Developer Artが書いたように)。
  • シリアル化可能なトランザクションを使用し、このロジックをビジネスレイヤーのC#で記述します.Count()
  • 何もせず、年に1回失敗させ、その後、混乱を解消します。

最後のオプションはおかしいと思うかもしれませんが、これは実際には深刻なオプションです。この種の並行性の問題を修正することは困難であり、至る所で行われる可能性があります。アーキテクチャに大きな変更を加える必要があるかもしれません。さらに、COUNT(*)ソリューションの有効性は、その特定のテーブルのインデックスによって異なります。(パフォーマンス上の理由で)データベースにインデックスを追加すると、このソリューションの有効性と正確性が誤って変更される可能性があります。したがって、ビジネスの観点からは、データベースの問題を1年に1回修正する方がはるかに安価な場合があります。もちろん、顧客があなたのビジネスよりも多くの注文を購入できるようになるたびに、コストが何であるかを推測することはできません。それはあなた(またはあなたのビジネス)が決定することです。

于 2010-04-27T13:30:17.753 に答える
1

これをDBレベルで処理したくない場合は、各製品の購入数を格納するクラスを作成し、それらの数をテーブルに格納して、購入方法にロックします。これはmutexメソッドに似ていますが、.NETがロックを処理できるようにします

public class PurchaseCounter(
{
    public Guid Product {get; set; } 
    public int MaxOrders {get; set; } 
    public int int CurrentOrders {get; set; } 
 }

public static bool Purchase(Product product, Client client)
{

    PurchaseCounter counter = purchaseCounterDictionary[product.ProductGuid];

    lock(counter)
    {
        if( counter.CurrentOrders < counter.MaxOrders )
        {
             //do logic to place order
             counter.CurrentOrders++;
             return true;  
        } 
        else
        {
             return false;
        }
    }

 }

}

于 2010-04-27T14:07:41.567 に答える