首页 > 其他分享 >操作筛选器的 1 个应用实例:自动启用事务

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

时间:2024-10-11 17:46:20浏览次数:10  
标签:事务 启用 app dbCtx 实例 TransactionScope using 筛选 builder

image

前言

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

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

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

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

Step By Step 步骤

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

  2. 引用 EF Core 项目 BooksEFCore

  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;
    			//判断操作方法上是否标注了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();
    		}
    	}
    }
    
  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

标签:事务,启用,app,dbCtx,实例,TransactionScope,using,筛选,builder
From: https://www.cnblogs.com/JackyGz/p/18458974

相关文章

  • NetCore 阿里云表格存储插入数据实例
    十年河东,十年河西,莫欺少年穷学无止境,精益求精帮助类:publicclassOtsHelper{publicstaticstringEndpoint="https://xxx.cn-shanghai.ots.aliyuncs.com";publicstaticstringInstanceName="xxx";///<summary>//......
  • 教你如何免费获取股票数据用python、JavaScript (Node.js)、JAVA等多种语言的实例代码
    ​近一两年来,股票量化分析逐渐受到广泛关注。而作为这一领域的初学者,首先需要面对的挑战就是如何获取全面且准确的股票数据。因为无论是实时交易数据、历史交易记录、财务数据还是基本面信息,这些数据都是我们进行量化分析时不可或缺的宝贵资源。我们的核心任务是从这些数据......
  • SMB签名是一种通过数字签名技术保障数据在网络传输过程中的完整性和来源验证的机制。
    SMB签名是ServerMessageBlock(SMB)协议中的一种安全机制,旨在确保数据的完整性和身份验证。1.什么是SMB签名?SMB签名是一种通过数字签名技术保障数据在网络传输过程中的完整性和来源验证的机制。它通过对数据进行哈希处理,并附加一个签名,确保接收方能够确认收到的数据没有被篡改。......
  • JavaScript Number研究03_实例方法_toExponential_toFixed_toPrecision_toString_valu
    JavaScriptNumber研究03:实例方法——toExponential、toFixed、toPrecision、toString、valueOf、toLocaleString在JavaScript中,Number对象不仅包含了许多有用的静态属性,还提供了一系列实例方法,帮助我们在不同场景下处理和转换数值。这些方法包括:toExponential()toFixed()......
  • 手把手教你学PCIE(6.9)--驱动程序开发实例的网络设备驱动程序开发
    目录1.开发环境准备1.1安装开发工具1.2创建项目目录2.驱动程序代码2.1驱动程序头文件2.2驱动程序主文件3.编译驱动程序4.加载和卸载驱动程序5.测试驱动程序6.总结开发一个网络设备驱动程序是一个复杂的任务,涉及到网络协议栈的集成和硬件设备的管理。在......
  • JAVAWEB实现文件上传下载功能实例解析
    需求:大文件上传,批量上传,断点续传,文件夹上传,大文件下载,批量下载,断点下载,文件夹下载文件夹:上传下载需要支持层级结构,采用非压缩方式文件大小:100G前端:vue2,vue3,vue-cli,jquery,html,webuploader后端:JSP,springbootweb服务:tomcat数据库:mysql,oracle,达梦,国产化数据库服务......
  • java 按行读取文件,并筛选包含指定字符行数据
    `importjava.io.BufferedReader;importjava.io.FileNotFoundException;importjava.io.FileReader;importjava.util.Collections;importjava.util.List;importjava.util.stream.Collectors;publicclassTestController{publicstaticvoidmain(String[]......
  • uniapp启用蓝牙
    <template> <viewclass="container"> <buttonclass="btn"@click="startBluetoothDevicesDiscovery">搜索蓝牙设备</button> <viewclass="device-list"> <viewv-for="(device,index)i......
  • Django路由和视图(筛选)
    温习温故知新1.路由分发方式一:includefromdjango.urlsimportpath,includeurlpatterns=[path('app/',include('app.urls'))]方式二:手工分发urlpatterns=[#path('user/login/',login,name='login'),#path('......
  • IIS 配置referer 请求筛选_请求拒绝
    一、IIS配置Referer拒绝   解析:访问静态内容,拒绝指定的referer,例如:拒绝后,对应的网站引用当前网站的静态资源会被拒绝。更多:iis怎么限制http下载速度_IIS限制网站带宽使用?IIS执行此操作时出错。详细信息:web.config错误,.netcore项目 IIS10隐藏httpserve......