什么是樂觀并發(fā)控制?
樂觀并發(fā)控制是一種處理并發(fā)訪問的數(shù)據(jù)的方法,它基于一種樂觀的假設(shè),即認(rèn)為并發(fā)訪問的數(shù)據(jù)沖突的概率很低。在樂觀并發(fā)控制中,系統(tǒng)不會(huì)立即對并發(fā)訪問的數(shù)據(jù)進(jìn)行加鎖,而是在數(shù)據(jù)被修改時(shí),再檢查是否有其他并發(fā)操作已經(jīng)修改了數(shù)據(jù)。如果檢測到?jīng)_突,系統(tǒng) 再采取相應(yīng)的措施來解決沖突。
EF Core 內(nèi)置了使用并發(fā)令牌列實(shí)現(xiàn)的樂觀并發(fā)控制,所謂的并發(fā)令牌列通常就是被并發(fā)操作影響的列。請看本文是如何在 EF Core 中使用樂觀并發(fā)控制的……
使用步驟
-
創(chuàng)建一個(gè) Asp.net console 項(xiàng)目,并從 Nuget 引用 EF 相關(guān)的包
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Tools -
配置并發(fā)沖突列
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; class HouseConfig : IEntityTypeConfiguration<House> { public void Configure(EntityTypeBuilder<House> builder) { builder.ToTable("T_Houses"); builder.Property(p => p.Name).IsUnicode().IsRequired(); // 把 Owner 列配置為并發(fā)令牌 builder.Property(p => p.Owner).IsConcurrencyToken(); } }
-
在 Program.cs 編寫以下代碼:
using Microsoft.EntityFrameworkCore; Console.WriteLine("請輸入您的姓名"); string name = Console.ReadLine()!; using TestDbContext ctx = new TestDbContext(); // 1.獲取數(shù)據(jù) var h1 = await ctx.Houses.SingleAsync(h => h.Id == 1); if (string.IsNullOrEmpty(h1.Owner)) { // 2.延遲5秒,方便測試 await Task.Delay(5000); // 3.更新數(shù)據(jù) h1.Owner = name; try { await ctx.SaveChangesAsync(); Console.WriteLine("搶到手了"); } catch(DbUpdateConcurrencyException ex) { // 4. 捕捉和處理并發(fā)沖突 var entry = ex.Entries.First(); var dbValues = await entry.GetDatabaseValuesAsync(); string newOwner = dbValues.GetValue<string>(nameof(House.Owner)); Console.WriteLine($"并發(fā)沖突,被{newOwner}提前搶走了"); } } // 5.處理數(shù)據(jù)已存在情況 else { if (h1.Owner == name) { Console.WriteLine("這個(gè)房子已經(jīng)是你的了,不用搶"); } else { Console.WriteLine($"這個(gè)房子已經(jīng)被{h1.Owner}搶走了"); } } Console.ReadLine();
-
測試
- 清理 T_Houses 表數(shù)據(jù),讓 Owner 列等于 null
- 同時(shí)運(yùn)行兩個(gè)控制臺(tái)程序
- 在第一個(gè)控制臺(tái)程序輸入 Tom 并運(yùn)行
- 在第二個(gè)控制臺(tái)程序輸入 Jim 并運(yùn)行
- 第一個(gè)控制臺(tái)返回消息:搶到手了
- 第二個(gè)控制臺(tái)則返回消息:并發(fā)沖突,被Tom提前搶走了
擴(kuò)展
-
通常可以通過把并發(fā)修改的屬性設(shè)置為并發(fā)令牌的方式啟用樂觀并發(fā)控制。
-
有時(shí)候無法確定到底哪個(gè)屬性適合作為并發(fā)令牌,比如程序在不同的情況下會(huì)更新不同的列或者程序會(huì)更新多個(gè)列,在這種情況下,可以使用設(shè)置一個(gè)額外的并發(fā)令牌屬性的方式來使用樂觀并發(fā)控制。
-
如果使用Microsoft SQL Server數(shù)據(jù)庫,可以用一個(gè)byte[]類型的屬性作為并發(fā)令牌屬性,然后使用IsRowVersion把這個(gè)屬性設(shè)置為RowVersion類型,這個(gè)屬性對應(yīng)的數(shù)據(jù)庫列就會(huì)被設(shè)置為ROWVERSION類型。對于ROWVERSION類型的列,在每次插入或更新行時(shí),Microsoft SQL Server會(huì)自動(dòng)為這一行的ROWVERSION類型的列生成新值。
1. 增加一個(gè)額外的byte[]類型的屬性 class House { public long Id { get; set; } public string Name { get; set; } public string? Owner { get; set; } public byte[] RowVer { get; set; } } 2. 配置并發(fā)令牌 builder.ToTable("T_Houses"); builder.Property(h => h.Name).IsUnicode(); builder.Property(h => h.RowVer).IsRowVersion(); 3. Update 語句中的 Where 中使用 RowVer 列
-
其它數(shù)據(jù)庫也可以使用 Guid 作為并發(fā)令牌控制文章來源:http://www.zghlxwxcb.cn/news/detail-762346.html
-
樂觀并發(fā)控制能夠避免悲觀鎖帶來的性能下降、死鎖等問題,推薦使用樂觀并發(fā)控制而不是悲觀鎖文章來源地址http://www.zghlxwxcb.cn/news/detail-762346.html
到了這里,關(guān)于如何在 EF Core 中使用樂觀并發(fā)控制的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!