本文转载自微信公众号「后端Q」,作者conan。转载本文请联系后端Q公众号。
控制事务
可以使用 DbContext.Database API 开始、提交和回滚事务。 以下示例显示了在单个事务中执行的两个 SaveChanges 操作以及一个 LINQ 查询:
- using var context = new BloggingContext();
- using var transaction = context.Database.BeginTransaction();
- try
- {
- context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });
- context.SaveChanges();
- context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/visualstudio" });
- context.SaveChanges();
- var blogs = context.Blogs
- .OrderBy(b => b.Url)
- .ToList();
- // Commit transaction if all commands succeed, transaction will auto-rollback
- // when disposed if either commands fails
- transaction.Commit();
- }
- catch (Exception)
- {
- // TODO: Handle failure
- }
虽然所有关系数据库提供程序都支持事务,但在调用事务 API 时,可能会引发其他提供程序类型或不执行任何操作。
使用 System.Transactions
如果需要跨较大作用域进行协调,则可以使用环境事务。
- using (var scope = new TransactionScope(
- TransactionScopeOption.Required,
- new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }))
- {
- using var connection = new SqlConnection(connectionString);
- connection.Open();
- try
- {
- // Run raw ADO.NET command in the transaction
- var command = connection.CreateCommand();
- command.CommandText = "DELETE FROM dbo.Blogs";
- command.ExecuteNonQuery();
- // Run an EF Core command in the transaction
- var options = new DbContextOptionsBuilder<BloggingContext>()
- .UseSqlServer(connection)
- .Options;
- using (var context = new BloggingContext(options))
- {
- context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });
- context.SaveChanges();
- }
- // Commit transaction if all commands succeed, transaction will auto-rollback
- // when disposed if either commands fails
- scope.Complete();
- }
- catch (Exception)
- {
- // TODO: Handle failure
- }
- }
还可以在显式事务中登记。
- using (var transaction = new CommittableTransaction(
- new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }))
- {
- var connection = new SqlConnection(connectionString);
- try
- {
- var options = new DbContextOptionsBuilder<BloggingContext>()
- .UseSqlServer(connection)
- .Options;
- using (var context = new BloggingContext(options))
- {
- context.Database.OpenConnection();
- context.Database.EnlistTransaction(transaction);
- // Run raw ADO.NET command in the transaction
- var command = connection.CreateCommand();
- command.CommandText = "DELETE FROM dbo.Blogs";
- command.ExecuteNonQuery();
- // Run an EF Core command in the transaction
- context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" });
- context.SaveChanges();
- context.Database.CloseConnection();
- }
- // Commit transaction if all commands succeed, transaction will auto-rollback
- // when disposed if either commands fails
- transaction.Commit();
- }
- catch (Exception)
- {
- // TODO: Handle failure
- }
- }
System.Transactions 的限制
- EF Core 依赖数据库提供程序以实现对 System.Transactions 的支持。 如果提供程序未实现对 System.Transactions 的支持,则可能会完全忽略对这些 API 的调用。 SqlClient 支持它。
- 自 .NET Core 2.1 起,System.Transactions 实现不包括对分布式事务的支持,因此不能使用 TransactionScope 或 CommittableTransaction 来跨多个资源管理器协调事务。