操作筛选器的 1 个应用实例:自动启用事务

news/2024/10/11 17:50:53

image

前言

在数据库操作过程中,有一个概念是绕不开的,那就是事务。

事务能够确保一系列数据库操作要么全部成功提交,要么全部失败回滚,保证数据的一致性和完整性。

在 Asp.Net Core Web API 中,我们可以使用操作筛选器给所有的数据库操作 API 加上事务控制,省心又省力,效果还很好。

看看 Step By Step 步骤是如何实现上述功能的。

Step By Step 步骤

  1. 创建一个 ASP.NET Core Web API 项目

  2. 引用 EF Core 项目 BooksEFCore

    • BooksEFCore 项目创建参见前文《EF Core 在实际开发中,如何分层?》
  3. 打开 appsettings.json,添加数据库连接串

    {"Logging": {"LogLevel": {"Default": "Information","Microsoft.AspNetCore": "Warning"}},"AllowedHosts": "*","ConnectionStrings": {"Default": "Server=(localdb)\\mssqllocaldb;Database=TestDB;Trusted_Connection=True;MultipleActiveResultSets=true"}
    }
    
  4. 创建一个自定义的 Attribute,用于给无需启用事务控制的操作方法

    [AttributeUsage(AttributeTargets.Method)]
    public class NotTransactionalAttribute:Attribute
    {}
    
  5. 编写自定义的操作筛选器 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;//判断操作方法上是否标注了NotTransactionalAttributehasNotTransactionalAttribute = 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();}}
    }
    
  6. 打开 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();
    
  7. 打开控制器,增加一个用于测试的操作方法(留意注释

    using Microsoft.AspNetCore.Mvc;namespace 自动启用事务的筛选器.Controllers
    {[ApiController][Route("[controller]/[action]")]public class TestController : ControllerBase{private readonly MyDbContext dbCtx;public TestController(MyDbContext dbCtx){this.dbCtx = dbCtx;}[HttpPost]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();}}
    }
    

总结

  1. 可以使用 TransactionScope 简化事务代码的编写。

  2. TransactionScope 是 .NET 中用来标记一段支持事务的代码的类。

  3. EF CoreTransactionScope 提供了天然的支持,当一段使用 EF Core 进行数据库操作的代码放到 TransactionScope 声明的范围中的时候,这段代码就会自动被标记为 "支持事务"

  4. TransactionScope 实现了 IDisposable 接口,如果一个 TransactionScope 的对象没有调用 Complete 就执行了 Dispose 方法,则事务会被回滚,否则事务就会被提交

  5. TransactionScope 还支持嵌套式事务,也就是多个 TransactionScope 嵌套,只有最外层的 TransactionScope 提交了事务,所有的操作才生效;如果最外层的 TransactionScope 回滚了事务,那么即使内层的 TransactionScope 提交了事务,最终所有的操作仍然会被回滚

  6. .NET Core 使用的 TransactionScope 支持的是 "最终一致性"。所谓的 "最终一致性",指的是在一段时间内,如果系统没有发生新的更新操作,那么所有副本的数据最终会达到一致的状态。换句话说,即使在系统中的不同节点上,数据的更新可能会有一段时间的延迟,但最终所有节点的数据会达到一致的状态。

  7. 在同步代码中,TransactionScope 使用 ThreadLocal 关联事务信息;

  8. 在异步代码中,TransactionScope 使用 AsyncLocal 关联事务信息

我是老杨,一个执着于编程乐趣、至今奋斗在一线的 10年+ 资深研发老鸟,是软件项目管理师,也是快乐的程序猿,持续免费分享全栈实用编程技巧、项目管理经验和职场成长心得!欢迎关注老杨的公众号(名称:代码掌控者),和你共同探索代码世界的奥秘!

image

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/70302.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

C# 线程---Thread1

1. thread 不带参数 (Main和Thread都在同步处理)(注意using static 和System.Console的使用)using static System.Console;namespace Recipe1 {class Program{static void Main(string[] args){Thread t = new Thread(PrintNumber);t.Start();PrintNumber();Read();}static…

解决 java.lang.VerifyError: Stack map does not match the one at exception

项目上用的liteflow,动态编译代码,在项目执行过程中报错如下: 拿到异常信息网上搜索,网上的说法如下: VM加载class文件时会做字节码校验(bytecode verification)。如果你的class文件是由java源文件通过javac编译出来的,那么基本上不用担心bytecode verification。 如果…

婚恋结构相亲管理系统的技术性分析

随着社会发展和人们对婚恋关系的重视,婚恋交友市场逐渐崛起。婚恋结构相亲管理系统作为该市场的重要解决方案,通过互联网平台将用户和服务提供者连接起来,帮助用户高效地寻找和管理自己的婚恋关系。本文将深入探讨婚恋结构相亲管理系统的技术架构、核心功能及其实现方式。一…

笔记本电脑蓝屏固态硬盘数据恢复

当笔记本电脑出现蓝屏故障,并且需要恢复固态硬盘中的数据时,可以参考以下步骤和建议: 一、初步处理与评估 断开电源:在尝试任何数据恢复操作之前,首先要断开笔记本电脑的电源,以避免进一步的数据损坏或丢失。 评估蓝屏原因:蓝屏可能是由多种原因引起的,如驱动程序错误、…

20222307 2024-2025-1 《网络与系统攻防技术》实验一实验报告

1. 实验内容 1.1本周学习内容 进程内存管理 在Linux系统中,当OS可执行程序被加载到内存后,其内存布局主要包括三个关键段: * .text段:包含程序的指令,这些指令是只读的,用于指导CPU执行操作。 * .data段:存储静态初始化数据,这些数据是可写的,程序在运行时可以直接访问…

WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

1、新建了一个用户控件,里面画了一个实心圆,以及一个文本控件的组合,当作我要实验使用的用户控件(TestUserControl)。2、在主窗体里面进行引用,可以看到引用以后,会在工具箱上显示新增的用户控件3、为了测试方便,我直接在先前的Login页面直接进行添加该用户控件,效果如下…

华为交换机配置-端口隔离

端口隔离(port-isolate) 1.端口隔离 配置端口隔离功能,可实现本台交换机的两个接口之间的二层数据的隔离,而三层数据互通 拓扑图<sw1>sys //配置全局端口隔离模式为二层隔离(l2)、三层隔离(l3) [sw1]port-isolate mode l2 [sw1]interface GigabitEthernet 0/0/1 …

Sublime

Sublime激活快捷键 Alt + F3 查找内容 全部选择,可以统一替换或 手动修改