操作筛选器的 1 个应用实例:自动启用事务
前言
在数据库操作过程中,有一个概念是绕不开的,那就是事务。
事务能够确保一系列数据库操作要么全部成功提交,要么全部失败回滚,保证数据的一致性和完整性。
在 Asp.Net Core Web API 中,我们可以使用操作筛选器给所有的数据库操作 API 加上事务控制,省心又省力,效果还很好。
看看 Step By Step 步骤是如何实现上述功能的。
Step By Step 步骤
[*]创建一个 ASP.NET Core Web API 项目
[*]引用 EF Core 项目 BooksEFCore
[*]BooksEFCore 项目创建参见前文《EF Core 在实际开发中,如何分层?》
[*]打开 appsettings.json,添加数据库连接串
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"Default": "Server=(localdb)\\mssqllocaldb;Database=TestDB;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}
[*]创建一个自定义的 Attribute,用于给无需启用事务控制的操作方法
public class NotTransactionalAttribute:Attribute
{
}
[*]编写自定义的操作筛选器 TransactionScopeFilter,用于自动启用事务控制(留意注释)
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Reflection;
using System.Transactions;
public class TransactionScopeFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(
ActionExecutingContext context,
ActionExecutionDelegate next)
{
bool hasNotTransactionalAttribute = false;
if (context.ActionDescriptor is ControllerActionDescriptor)
{
var actionDesc = (ControllerActionDescriptor)context.ActionDescriptor;
//判断操作方法上是否标注了NotTransactionalAttribute
hasNotTransactionalAttribute = actionDesc.MethodInfo.IsDefined(typeof(NotTransactionalAttribute));
}
//如果操作方法标注了NotTransactionalAttribute,直接执行操作方法
if (hasNotTransactionalAttribute)
{
await next();
return;
}
//如果操作方法没有标注NotTransactionalAttribute,启用事务
using var txScope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled);
var result = await next();
if (result.Exception == null)
{
txScope.Complete();
}
}
}
[*]打开 Program.cs,注册这个操作筛选器
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// 注册数据库服务
builder.Services.AddDbContext<MyDbContext>(opt => {
string connStr = builder.Configuration.GetConnectionString("Default");
opt.UseSqlServer(connStr);
});
// 注册自动启用事务过滤器
builder.Services.Configure<MvcOptions>(opt => {
opt.Filters.Add<TransactionScopeFilter>();
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
[*]打开控制器,增加一个用于测试的操作方法(留意注释)
using Microsoft.AspNetCore.Mvc;
namespace 自动启用事务的筛选器.Controllers
{
/")]
public class TestController : ControllerBase
{
private readonly MyDbContext dbCtx;
public TestController(MyDbContext dbCtx)
{
this.dbCtx = dbCtx;
}
public async Task Save()
{
dbCtx.Books.Add(new Book { Id = Guid.NewGuid(), Name = "1", Price = 1 });
await dbCtx.SaveChangesAsync();
dbCtx.Books.Add(new Book { Id = Guid.NewGuid(), Name = "2", Price = 2 });
await dbCtx.SaveChangesAsync();
// 以上代码能够正确地插入两条数据
// 如果启用以下代码抛出异常,将不会插入数据
// 说明事务起作用,数据被回滚了
// throw new Exception();
}
}
}
总结
[*]可以使用 TransactionScope 简化事务代码的编写。
[*]TransactionScope 是 .NET 中用来标记一段支持事务的代码的类。
[*]EF Core 对 TransactionScope 提供了天然的支持,当一段使用 EF Core 进行数据库操作的代码放到 TransactionScope 声明的范围中的时候,这段代码就会自动被标记为 "支持事务"
[*]TransactionScope 实现了 IDisposable 接口,如果一个 TransactionScope 的对象没有调用 Complete 就执行了 Dispose 方法,则事务会被回滚,否则事务就会被提交
[*]TransactionScope 还支持嵌套式事务,也就是多个 TransactionScope 嵌套,只有最外层的 TransactionScope 提交了事务,所有的操作才生效;如果最外层的 TransactionScope 回滚了事务,那么即使内层的 TransactionScope 提交了事务,最终所有的操作仍然会被回滚
[*].NET Core 使用的 TransactionScope 支持的是 "最终一致性"。所谓的 "最终一致性",指的是在一段时间内,如果系统没有发生新的更新操作,那么所有副本的数据最终会达到一致的状态。换句话说,即使在系统中的不同节点上,数据的更新可能会有一段时间的延迟,但最终所有节点的数据会达到一致的状态。
[*]在同步代码中,TransactionScope 使用 ThreadLocal 关联事务信息;
[*]在异步代码中,TransactionScope 使用 AsyncLocal 关联事务信息
我是老杨,一个执着于编程乐趣、至今奋斗在一线的 10年+ 资深研发老鸟,是软件项目管理师,也是快乐的程序猿,持续免费分享全栈实用编程技巧、项目管理经验和职场成长心得!欢迎关注老杨的公众号(名称:代码掌控者),和你共同探索代码世界的奥秘!
来源:https://www.cnblogs.com/JackyGz/p/18458974
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
页:
[1]