EFCore 5 新特性 Savepoints
EFCore 5 中的 Savepoints
Intro
EFCore 5中引入了一個(gè)新特性,叫做 Savepoints,主要是事務(wù)中使用,個(gè)人感覺(jué)有點(diǎn)類(lèi)似于 Windows 上的系統(tǒng)還原點(diǎn),如果事務(wù)發(fā)生了異常,可以回滾到某一個(gè)還原點(diǎn)。
Savepoints
當(dāng)我們?cè)谝粋€(gè)事務(wù)里執(zhí)行 SaveChanges 的時(shí)候,EF Core 會(huì)在保存數(shù)據(jù)之前自動(dòng)的創(chuàng)建一個(gè) savepoint,Savepoints 有點(diǎn)類(lèi)似于系統(tǒng)還原點(diǎn)的概念,我們可以回滾到指定的 savepoint,
當(dāng)事務(wù)發(fā)生錯(cuò)誤的時(shí)候,會(huì)自動(dòng)回滾到事務(wù)創(chuàng)建的 savepoint 回滾到事務(wù)開(kāi)始之前的狀態(tài),以便于我們做重試或可能的修復(fù)錯(cuò)誤或其他邏輯。
我們可以通過(guò) CreateSavepoint 來(lái)手動(dòng)創(chuàng)建一個(gè) savepoint,使用 RollbackToSavepoint 來(lái)回滾到某一個(gè) savepoint
來(lái)看一個(gè)微軟的示例代碼吧:
using?var?context?=?new?BloggingContext(); using?var?transaction?=?context.Database.BeginTransaction();try {context.Blogs.Add(new?Blog?{?Url?=?"https://devblogs.microsoft.com/dotnet/"?});context.SaveChanges();transaction.CreateSavepoint("BeforeMoreBlogs");context.Blogs.Add(new?Blog?{?Url?=?"https://devblogs.microsoft.com/visualstudio/"?});context.Blogs.Add(new?Blog?{?Url?=?"https://devblogs.microsoft.com/aspnet/"?});context.SaveChanges();transaction.Commit(); } catch?(Exception) {//?If?a?failure?occurred,?we?rollback?to?the?savepoint?and?can?continue?the?transactiontransaction.RollbackToSavepoint("BeforeMoreBlogs");//?TODO:?Handle?failure,?possibly?retry?inserting?blogs }Sample
我們自己來(lái)動(dòng)手一試,示例代碼如下:
var?services?=?new?ServiceCollection(); services.AddDbContext<TestDbContext>(options?=> {options.UseSqlite("Data?Source=Application.db;Cache=Shared").LogTo(Console.WriteLine,?LogLevel.Warning); }); using?var?provider?=?services.BuildServiceProvider(); using?var?scope?=?provider.CreateScope(); var?dbContext?=?scope.ServiceProvider.GetRequiredService<TestDbContext>(); dbContext.Database.EnsureCreated(); Console.WriteLine($"Posts?count:{dbContext.Posts.Count()}"); using?var?transaction?=?dbContext.Database.BeginTransaction(); try {dbContext.Posts.Add(new?Post()?{?Author?=?"Tom",?Title?=?"Date?changed",?PostedAt?=?DateTime.UtcNow,?});dbContext.Posts.Add(new?Post()?{?Author?=?"Tom",?Title?=?"Date?changed",?PostedAt?=?DateTime.UtcNow,?});dbContext.SaveChanges();transaction.CreateSavepoint("Stage1");Console.WriteLine($"Posts?count:{dbContext.Posts.Count()}");dbContext.Posts.Add(new?Post()?{?Author?=?"Alice",?Title?=?"Test",?PostedAt?=?DateTime.UtcNow,?});dbContext.SaveChanges();transaction.CreateSavepoint("Stage2");Console.WriteLine($"Posts?count:{dbContext.Posts.Count()}");throw?new?InvalidOperationException();transaction.Commit(); } catch?(Exception) {Console.WriteLine("Exception?throw");transaction.RollbackToSavepoint("Stage1"); }Console.WriteLine($"Posts?count:{dbContext.Posts.Count()}");示例代碼中創(chuàng)建了兩個(gè) savepoint,然后拋出了一個(gè)異常,捕獲異常后回滾到第一個(gè) savepoint
輸出結(jié)果如下:
output可以看到,只有第一個(gè) savepoint 之前的數(shù)據(jù)保存了下來(lái),第二個(gè) savepoint 雖然數(shù)據(jù)成功保存了,但是又被回滾了,最終只有第一個(gè) savepoint 之前的數(shù)據(jù)變更被保存了下來(lái)
More
通過(guò) savepoint 我們就可以使得事務(wù)控制更加精細(xì),可以更能夠好的控制事務(wù)中的數(shù)據(jù)變更
但是需要注意的是,這個(gè)功能不要和 Sql Server 中的 Multiple Active Result Sets 一起使用,一旦發(fā)生了錯(cuò)誤,事務(wù)控制可能會(huì)發(fā)生不可預(yù)期的情況。
Savepoints are incompatible with SQL Server's Multiple Active Result Sets, and are not used. If an error occurs during SaveChanges, the transaction may be left in an unknown state.
References
https://docs.microsoft.com/en-us/ef/core/saving/transactions#savepoints
https://github.com/WeihanLi/SamplesInPractice/blob/master/EF5Samples/SavePointsTest.cs
總結(jié)
以上是生活随笔為你收集整理的EFCore 5 新特性 Savepoints的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 如何在 Blazor WebAssemb
- 下一篇: AWS 宣布创建“真正”开源的 Elas