[英]Violation of PRIMARY KEY constraint on insert
我有一個簡單的表:
IPAddress (PK, string)
Requests (int)
這是一個洪水限制器。 表格數據每分鍾都會刪除一次。 對於每個頁面請求,給定IPAddress
的Requests
計數都會增加。
它運作良好,並且由於我們產品和網站的性質,我們確實遭受了一些偶然/故意有效的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.