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

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

在實體框架核心中執(zhí)行業(yè)務規(guī)則

在實體框架核心中執(zhí)行業(yè)務規(guī)則

C#
精慕HU 2022-11-13 13:46:40
假設我有一個執(zhí)行以下操作的控制器操作:檢查在特定時間是否有日歷槽檢查是否沒有已預訂的約會與該時段重疊如果兩個條件都滿足,它會在給定時間創(chuàng)建一個新約會簡單的實現(xiàn)會帶來多個問題:如果在第 3 步之前刪除了 1 中獲取的日歷槽怎么辦?如果在第 2 步之后但第 3 步之前預約了另一個約會怎么辦?這些問題的解決方案似乎是使用 SERIALIZABLE 事務隔離級別。問題是每個人似乎都認為這種事務隔離級別非常危險,因為它可能導致死鎖。給出以下簡單的解決方案:public class AController{    // ...    public async Task Fn(..., CancellationToken cancellationToken)    {        var calendarSlotExists = dbContext.Slots.Where(...).AnyAsync(cancellationToken);        var appointmentsAreOverlapping = dbContext.Appointments.Where(...).AnyAsync(cancellationToken);        if (calendarSlotExists && !appointmentsAreOverlapping)            dbContext.Appointments.Add(...);        dbContext.SaveChangesAsync(cancellationToken);    }}始終防止并發(fā)問題的最佳方法是什么,我應該如何處理最終的死鎖?
查看完整描述

3 回答

?
明月笑刀無情

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

數(shù)據(jù)庫完整性檢查是您最好的朋友

根據(jù)您的描述,您的約會是基于時段的。這使問題變得簡單得多,因為您可以有效地為表定義唯一SlotId約束Appointments。然后你需要一個外鍵作為Appointments.SlotId參考Slot.Id

如果在第 3 步之前刪除了 1 中獲取的日歷槽怎么辦?

數(shù)據(jù)庫會拋出外鍵違規(guī)異常

如果在第 2 步之后但第 3 步之前預約了另一個約會怎么辦?

DB 會拋出重復鍵異常

接下來您需要做的是捕捉這兩個異常并將用戶重定向回預訂頁面。再次從數(shù)據(jù)庫重新加載數(shù)據(jù)并檢查任何無效條目,通知用戶進行修改并重試。

對于死鎖部分,它實際上取決于您的表結構。訪問數(shù)據(jù)的方式、索引它們的方式以及數(shù)據(jù)庫的查詢計劃。對此沒有確定的答案。


查看完整回答
反對 回復 2022-11-13
?
智慧大石

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

看來您需要一種悲觀的并發(fā)方法來管理您的任務。不幸的是,它在 Entity Framework Core 中不受支持。


或者,您可以使用靜態(tài) ConcurrentDictionary 或?qū)崿F(xiàn)您自己的 ConcurrentHashSet 以防止多個請求并避免在第 2 步之后但在第 3 步之前預訂另一個約會。


關于在步驟 3 問題之前刪除 1 中獲取的日歷槽,我認為在 Appointment 和 Slot 之間有一個外鍵關系來檢查 SaveChanges 處的數(shù)據(jù)庫完整性,或者讓 ConcurrentDictionary/ConcurrentHashSet Public 并從另一個操作中檢查它(刪除 Slots,等)在執(zhí)行它們之前,是解決它的好選擇。


static ConcurrentDictionary<int, object> operations = new ConcurrentDictionary<int, object>();


    public async Task<IActionResult> AControllerAction()

    {

        int? calendarSlotId = 1; //await dbContext.Slots.FirstOrDefaultAsync(..., cancellationToken))?.Id;


        try

        {

            if (calendarSlotId != null && operations.TryAdd(calendarSlotId.Value, null))

            {

                bool appointmentsAreOverlapping = false; //await dbContext.Slots.Where(...).AnyAsync(cancellationToken);


                if (!appointmentsAreOverlapping)

                {

                    //dbContext.Appointments.Add(...);

                    //await dbContext.SaveChangesAsync(cancellationToken);


                    return ...; //All done!

                }


                return ...; //Appointments are overlapping

            }


            return ...; //There is no slot or slot is being used

        }

        catch (Exception ex)

        {

            return ...; //ex exception (DB exceptions, etc)

        }

        finally

        {

            if (calendarSlotId != null)

            {

                operations.TryRemove(calendarSlotId.Value, out object obj);

            }

        }

    }


查看完整回答
反對 回復 2022-11-13
?
Cats萌萌

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

有時,在高可用性場景中,建議權衡即時一致性(通過事務獲得)以換取最終一致性(通過工作流/傳奇獲得)。


在您的示例中,您可以考慮一種方法,該方法使用中間狀態(tài)來存儲“待定”約會,然后對其一致性進行新的檢查。


public async Task Fn(..., CancellationToken cancellationToken)

{

    // suppose "appointment" is our entity, we will store it as "pending" using

    // PendingUntil property (which is Nullable<DateTimeOffset>).

    // an appointment is in "pending" state if the PendingUntil property is set

    // (not null), and its value is >= UtcNow

    var utcNow = DateTimeOffset.UtcNow;

    appointment.PendingUntil = utcNow.AddSeconds(5);


    // we will then use this property to find out if there are other pending appointments


    var calendarSlotExists = await dbContext.Slots.Where(...).AnyAsync(cancellationToken);

    var appointmentsAreOverlapping = await dbContext.Appointments

                                                    .Where(...)

                                                    .Where(a => a.PendingUntil == null || 

                                                                a.PendingUntil >= now)

                                                    .AnyAsync(cancellationToken);


    if (calendarSlotExists && !appointmentsAreOverlapping)

        dbContext.Appointments.Add(appointment);

    else

        return BadRequest(); // whatever you what to return


    await dbContext.SaveChangesAsync(cancellationToken); // save the pending appointment


    // now check if the pending appointment is still valid


    var calendarSlotStillExists = await dbContext.Slots.Where(...).AnyAsync(cancellationToken); // same query as before


    // a note on the calendar slot existance: you should of course negate any

    // slot deletion for (pending or not) appointments.


    // we will then check if there is any other appointment in pending state that was

    // stored inside the database "before" this one.

    // this query is up to you, below you'll find just an example


    var overlappingAppointments = await dbContext.Appointments.Where(...)

                                                 .Where(a => a.Id != appointment.Id &&

                                                             a.PendingUntil == null || 

                                                             a.PendingUntil >= now)

                                                 .ToListAsync(cancellationToken);


    // we are checking if other appointments (pending or not) have been written to the DB

    // of course we need to exclude the appointment we just added


    if (!calendarSlotStillExists || overlappingAppointments.Any(a => a.PendingUntil == null || a.PendingUntil < appointment.PendingUntil)

    {

        // concurrency check failed

        // this means that another appointment was added after our first check, but before our appointment.

        // we have to remove the our appointment

        dbContext.Appointments.Remove(appointment);

        await dbContext.SaveChangesAsync(cancellationToken); // restore DB

        return BadRequest(); // same response as before

    }


    // ok, we can remove the pending state

    appointment.PendingUntil = null;


    await dbContext.SaveChangesAsync(cancellationToken); // insert completed

    return Ok();

}

當然,這會對數(shù)據(jù)庫造成雙重打擊,但會完全避免事務(帶有死鎖和鎖定延遲)。


您只需要評估哪個方面對您更重要:可擴展性或即時一致性。


查看完整回答
反對 回復 2022-11-13
  • 3 回答
  • 0 關注
  • 108 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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