EFCore 5中引入了一個新特性,叫作 Savepoints
,主要是事務中使用,我的感受有點相似於 Windows 上的系統還原點,若是事務發生了異常,能夠回滾到某一個還原點。git
當咱們在一個事務裏執行 SaveChanges
的時候,EF Core 會在保存數據以前自動的建立一個 savepoint
,Savepoints
有點相似於系統還原點的概念,咱們能夠回滾到指定的 savepoint
,github
當事務發生錯誤的時候,會自動回滾到事務建立的 savepoint
回滾到事務開始以前的狀態,以便於咱們作重試或可能的修復錯誤或其餘邏輯。ide
咱們能夠經過 CreateSavepoint
來手動建立一個 savepoint
,使用 RollbackToSavepoint
來回滾到某一個 savepoint
ui
來看一個微軟的示例代碼吧:code
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 transaction transaction.RollbackToSavepoint("BeforeMoreBlogs"); // TODO: Handle failure, possibly retry inserting blogs }
咱們本身來動手一試,示例代碼以下:blog
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()}");
示例代碼中建立了兩個 savepoint
,而後拋出了一個異常,捕獲異常後回滾到第一個 savepoint
事務
輸出結果以下:ip
能夠看到,只有第一個 savepoint
以前的數據保存了下來,第二個 savepoint
雖然數據成功保存了,可是又被回滾了,最終只有第一個 savepoint
以前的數據變動被保存了下來get
經過 savepoint
咱們就可使得事務控制更加精細,能夠更可以好的控制事務中的數據變動it
可是須要注意的是,這個功能不要和 Sql Server 中的 Multiple Active Result Sets 一塊兒使用,一旦發生了錯誤,事務控制可能會發生不可預期的狀況。
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.