第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

當行存在時,F(xiàn)irstOrDefault 返回 null

當行存在時,F(xiàn)irstOrDefault 返回 null

PHP
瀟瀟雨雨 2024-01-20 15:48:37
我遇到了一些競爭條件,其中數(shù)據(jù)庫中的一行可能由兩個線程同時創(chuàng)建。為了解決這個問題,我實現(xiàn)了重試,如下所示:int retries = 0;while (true){? ? ? ? ? ? ? ??? ? try? ? {? ? ? ? var saved = context.Table.FirstOrDefault(x => x.field1 == val1 && x.field2 == val2);? ? ? ? if (saved != null)? ? ? ? {? ? ? ? ? ? //edits saved? ? ? ? }? ? ? ? else? ? ? ? {? ? ? ? ? ? context.Table.Add(new Table? ? ? ? ? ? {? ? ? ? ? ? ? ? field1 = val1,? ? ? ? ? ? ? ? field2 = val2? ? ? ? ? ? });? ? ? ? }? ? ? ? await context.SaveChangesAsync();? ? ? ? return Json(true);? ? }? ? catch (Exception e)? ? {? ? ? ? if (retries >= 5)? ? ? ? ? ? throw (e);? ? ? ? retries++;? ? }}不知何故,連續(xù)失敗 5 次,并出現(xiàn)相同的錯誤:Microsoft.EntityFrameworkCore.DbUpdateException:更新條目時發(fā)生錯誤。有關詳細信息,請參閱內部異常。---> System.Data.SqlClient.SqlException:無法在具有唯一索引“IX_Table_field1_field2”的對象“dbo.Table”中插入重復的鍵行。重復的鍵值為(val1, val2)。即使數(shù)據(jù)庫中明確存在該行,為什么 FirstOrDefault 返回 null?我正在使用 Microsoft.AspNetCore.All v.2.1.4上下文不在線程之間共享。當多個 HTTP 請求同時到達時,就會發(fā)生競爭。上下文被注入到控制器(此代碼所在的位置)。它使用默認設置通過 AddDbContext 調用進行注冊,使其具有 ServiceLifetime 作用域。添加但未保存的行保留在上下文中并繼續(xù)嘗試插入。我保留了對新行的引用并將其添加到 catch 塊中:context.Entry(NewRow).State?=?EntityState.Detached;
查看完整描述

3 回答

?
守著一只汪

TA貢獻1872條經(jīng)驗 獲得超4個贊

你分享了嗎DbContext?DbContext 不是線程安全的。


嘗試將插入操作包裝在 的using塊中DbContext,而不是重試:


using(var context = new DbContext)

{

? // Insert operation here

}

這種沖突很容易理解,但首先你需要知道,當你await調用時,線程立即返回到調用者。

想象一下這個場景,您有兩個線程正在運行您的代碼。這是執(zhí)行順序:

  1. 線程 1:FirstOrDefault返回null.

  2. 線程 2:FirstOrDefault返回null.

  3. 線程 1:Add運行。SQL 生成并在數(shù)據(jù)庫服務器上排隊。

  4. 主題 1:await context.SaveChangesAsync().?呼叫立即完成。

  5. 數(shù)據(jù)庫:線程 1 的調用已完成。

  6. 線程2:Add運行。SQL 生成并在數(shù)據(jù)庫服務器上排隊。

  7. 主題 2:await context.SaveChangesAsync().?呼叫立即完成。

  8. 數(shù)據(jù)庫:嘗試從線程 2 進行調用,但無法完成它,因為之前插入了具有相同鍵值的行。


查看完整回答
反對 回復 2024-01-20
?
侃侃無極

TA貢獻2051條經(jīng)驗 獲得超10個贊

如果數(shù)據(jù)庫中有一條記錄作為val1鍵但val2不同,firstOrDefault()則不會返回值,并且您仍然無法插入新記錄。

這也可能是緩存問題。您可以嘗試添加AsNoTracking()到您的查詢中。


查看完整回答
反對 回復 2024-01-20
?
largeQ

TA貢獻2039條經(jīng)驗 獲得超8個贊

重試不起作用,因為一旦您將條目添加到上下文并收到?jīng)_突錯誤,條目仍標記為已插入,因此您將在所有進一步的重試中嘗試插入它。您需要使用新的上下文或將其分離才能使重試起作用。

交易

如果您想確保在嘗試查找記錄時沒有人可以添加記錄,那么您需要使用事務:

using (var context = new MyContext())

using (var transaction = context.Database.BeginTransaction(IsolationLevel.Serializable)) {

? ? ? ? var saved = context.Table.FirstOrDefault(x => x.field1 == val1 && x.field2 == val2);

? ? ? ? if (saved != null)

? ? ? ? {

? ? ? ? ? ? //edits saved

? ? ? ? }

? ? ? ? else

? ? ? ? {

? ? ? ? ? ? context.Table.Add(new Table

? ? ? ? ? ? {

? ? ? ? ? ? ? ? field1 = val1,

? ? ? ? ? ? ? ? field2 = val2

? ? ? ? ? ? });

? ? ? ? }

? ? ? ? await context.SaveChangesAsync();

? ? ? ? transaction.Commit()

? ? ? ? return Json(true);

}

我在這里使用最隔離的級別來鎖定表并防止讀取時的競爭條件。此方法會對性能產生影響,如果可以接受重試,您仍然可以遵循此方法。

更新插入

如果您擁有新實體所需的所有數(shù)據(jù),那么您可以使用FlexLabs.Upsert?-update或者insert將在單個事務中執(zhí)行,這樣您就不會再發(fā)生沖突。

重試

請注意,如果更新不是冪等的,您可能仍然存在競爭條件,但現(xiàn)在您將其移至數(shù)據(jù)庫端:2 個線程找到一個項目,單獨更新并保存。您可以按照本文所述使用并發(fā)令牌來避免此類沖突。請記住,如果您堅持重試選項,更新必須是冪等的,這意味著無論有多少線程都會更新實體 - 它將與第一次更新后相同。

有一個很棒的框架Polly.NET對您來說非常方便:

await?Policy.Handle<DbUpdateException>()
????????????.RetryAsync(5)
????????????.ExecuteAsync(()?=>?...);

我不建議在 DbContext (或其他任何東西)上使用任何進程內鎖,因為這會限制您使用此邏輯運行單個進程,而當您需要高可用性時,情況并非如此。


查看完整回答
反對 回復 2024-01-20
  • 3 回答
  • 0 關注
  • 255 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網(wǎng)微信公眾號