簡體   English   中英

插入時違反PRIMARY KEY約束

[英]Violation of PRIMARY KEY constraint on insert

我有一個簡單的表:

IPAddress (PK, string)
Requests (int)

這是一個洪水限制器。 表格數據每分鍾都會刪除一次。 對於每個頁面請求,給定IPAddressRequests計數都會增加。

它運作良好,並且由於我們產品和網站的性質,我們確實遭受了一些偶然/故意有效的DDOS,因此我們的網站性能得到了顯着提高。

唯一的問題是,無論出於何種原因,當IP確實每分鍾都會向我們的網站發送數千個請求時,我們會彈出以下錯誤消息:

違反主鍵約束'PK_v2SiteIPRequests'。 無法在對象“ dbo.v2SiteIPRequests”中插入重復的密鑰。 重復的鍵值為([IP_ADDRESS])。 該語句已終止。

進行插入的代碼是:

/// <summary>
/// Call everytime a page view is requested
/// </summary>
private static void DoRequest(string ipAddress)
{
    using (var db = new MainContext())
    {
        var rec = db.v2SiteIPRequests.SingleOrDefault(c => c.IPAddress == ipAddress);
        if (rec == null)
        {
            var n = new v2SiteIPRequest {IPAddress = ipAddress, Requests = 1};
            db.v2SiteIPRequests.InsertOnSubmit(n);
            db.SubmitChanges();
        }
        else
        {
            rec.Requests++;
            db.SubmitChanges();

            // Ban?
            if (rec.Requests >= Settings.MAX_REQUESTS_IN_INTERVAL)
            {
                BanIP(ipAddress);
            }
        }
    }
}

處理此異常的最佳方法是什么,為什么會拋出該異常? 這是最好的try catch嗎?

如果您同時收到兩個請求,則會發生以下情況:

Request one: is it in the database?
Request two: is it in the database?

Request one: No, not yet
Request two: No, not yet

Request one: INSERT
Request two: INSERT

Request one: WORKS
Request two: FAILS (already inserted a split second before)

您無法在此處執行任何操作,但要捕獲異常並優雅地對其進行處理。 也許通過使用簡單的“重試”邏輯。

您那里有一些競爭條件,尤其是在存在並發連接時。

您可能需要更改方法,並始終存儲每個請求,然后查詢時間范圍內是否超出允許的范圍,並采取所需的任何操作

這是基於建議的解決方案。 這很丑,但據我所知可以正常工作。

/// <summary>
/// Call everytime a page view is requested
/// </summary>
private static void DoRequest(string ipAddress)
{
    using (var db = new MainContext())
    {
        var rec = db.v2SiteIPRequests.SingleOrDefault(c => c.IPAddress == ipAddress);
        if (rec == null)
        {
            // Catch insert race condition for PK violation.  Especially susceptible when being hammered by requests from 1 IP
            try
            {
                var n = new v2SiteIPRequest {IPAddress = ipAddress, Requests = 1};
                db.v2SiteIPRequests.InsertOnSubmit(n);
                db.SubmitChanges();
            }
            catch (Exception e)
            {
                try
                {
                    // Can't reuse original context as it caches
                    using (var db2 = new MainContext())
                    {
                        var rec2 = db2.v2SiteIPRequests.Single(c => c.IPAddress == ipAddress);
                        rec2.Requests++;
                        db2.SubmitChanges();
                        if (rec2.Requests >= Settings.MAX_REQUESTS_IN_INTERVAL)
                        {
                            BanIP(ipAddress);
                        }
                    }
                }
                catch (Exception ee)
                {
                    // Shouldn't reach here
                    Error.Functions.NewError(ee);
                }
            }
        }
        else
        {
            rec.Requests++;
            db.SubmitChanges();

            // Ban?
            if (rec.Requests >= Settings.MAX_REQUESTS_IN_INTERVAL)
            {
                BanIP(ipAddress);
            }
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM