Azure UNIQUE KEY 約束上的 SQL Server 數據庫崩潰
昨天啟動我們軟體的促銷活動後,我們的 SQL Server 數據庫遇到了一些奇怪的問題。當使用者在我們的網站上註冊帳戶時會發生此錯誤。當它是低使用者流量時,一切似乎都很好並且工作正常,但是一旦流量增加到一次約 10 個註冊,一切都會下降。一旦它停止對數據庫的每個以下請求,就會引發錯誤。修復它的唯一方法是重新啟動網站(直到下一次崩潰等等)。
這是錯誤:
違反 UNIQUE KEY 約束“AK_Users_Username”。無法在對象“dbo.Users”中插入重複鍵。重複鍵值為(使用者名)。該語句已終止。
(即使我們在添加之前檢查了使用者名)
還發生了另一個錯誤:
不允許新事務,因為會話中還有其他執行緒在執行。
這是一段將其添加到數據庫的
User程式碼License:var db = new CBEntities(); var user = db.Users.Add(new User { Username = model.Username, Firstname = model.FirstName, Lastname = model.LastName, Email = model.Email, Password = model.Password, EmailConfirmed = 0, Country = model.Country, EmailSubscribed = model.Newsletter != null && model.Newsletter.Value ? 1 : 0, Role = "User", SignUpDate = DateTime.UtcNow }); db.SaveChanges(); //create a initial trial license for user var lic = db.Licenses.Add(new License { ExpirationDate = DateTime.UtcNow.AddDays(21), UserID = user.ID, Key = "", PackageID = coupon.ID, Status = (int)LicenseStatus.Active, Type = (int)LicenseTypes.TRIAL }); db.SaveChanges(); user.LicenseID = lic.ID; db.SaveChanges();站點和數據庫在 Azure 主機上執行。我們確實將網站擴展到標準計劃,它甚至使用了幾個具有 2 個核心和 3.5 Gb 記憶體的實例。它沒有解決錯誤。數據庫目前具有 S2 性能的標準服務層。等級。(它連結到網站)..
當沒有高使用者流量時,一切正常!
請幫助我們找到解決方案
你的程式碼結構是這樣的。
- 檢查重複的使用者名
- 添加使用者
- 將使用者保存到數據庫
- 添加許可證
- 將許可證保存到數據庫
- 將許可證與使用者關聯
這裡每個操作,如創建使用者、創建許可證和關聯許可證都是單獨的原子操作。您應該擁有的是所有這些動作一起應該被認為是原子的。我強烈建議有一個事務邊界來考慮使用者創建、許可證創建及其關聯一個單一的原子單元,而不是單獨處理它們。
關於唯一鍵錯誤
違反 UNIQUE KEY 約束“AK_Users_Username”。無法在對象“dbo.Users”中插入重複鍵。重複鍵值為(使用者名)。該語句已終止。
在上面的序列中,可以有 2 個不同的連接檢查相同的使用者名“abc.def”並嘗試創建使用者。但是,這些請求中只有一個能夠在數據庫中創建新的使用者記錄。
第二條記錄將因違反唯一鍵約束而失敗。
您可以通過在創建使用者之前再次檢查使用者名來最大限度地減少此類錯誤。這不會完全消除錯誤,但會盡量減少此類事件的發生。
徹底消除此類錯誤
- 啟動一個可序列化的事務
- 再次檢查使用者名
- 進行正常處理…
- 將許可證與使用者關聯
- 送出交易
注意:使用 Serializable 範圍可能會導致阻塞,因為這是最孤立的範圍。
可序列化的參考文章
希望這可以幫助
您沒有
DbContext在 using 語句中包含 。它應該像這樣處理:using (var db = new CBEntities()) { var user = db.Users.Add(new User { Username = model.Username, Firstname = model.FirstName, Lastname = model.LastName, Email = model.Email, Password = model.Password, EmailConfirmed = 0, Country = model.Country, EmailSubscribed = model.Newsletter != null && model.Newsletter.Value ? 1 : 0, Role = "User", SignUpDate = DateTime.UtcNow }); db.SaveChanges(); //create a initial trial license for user var lic = db.Licenses.Add(new License { ExpirationDate = DateTime.UtcNow.AddDays(21), UserID = user.ID, Key = "", PackageID = coupon.ID, Status = (int)LicenseStatus.Active, Type = (int)LicenseTypes.TRIAL }); db.SaveChanges(); user.LicenseID = lic.ID; db.SaveChanges(); }處理
DbContext關閉與數據庫的連接。這可以解釋為什麼不處理 DbContext 會導致太多連接錯誤。當您在站點上幾乎沒有活動時,連接超時,這解釋了為什麼您在輕負載下沒有錯誤。