From 0039f37f8dde3a70dd0054b3089afba49a2e2899 Mon Sep 17 00:00:00 2001 From: bunny <1319900154@qq.com> Date: Thu, 5 Sep 2024 14:26:31 +0800 Subject: [PATCH] =?UTF-8?q?:recycle:=20feat(=E6=96=B0=E5=A2=9E):=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=B9=E6=B3=95=E4=B8=8A=E7=9A=84=E4=BA=8B?= =?UTF-8?q?=E5=8A=A1=E6=B3=A8=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Attribute/TransactionAttribute.cs | 6 +++ .../Context/Database/EFCoreContext.cs | 2 +- .../Database/TransactionInterceptor.cs | 34 ---------------- .../Filter/TransactionIAsyncActionFilter.cs | 39 +++++++++++++++++++ Bunny.Service/IService/Service/BlogService.cs | 8 ++-- .../Configuration/ServiceRegistration.cs | 1 + Bunny.WebApi/ReadMe/ReadMe.md | 4 +- 7 files changed, 55 insertions(+), 39 deletions(-) create mode 100644 Bunny.Common/Attribute/TransactionAttribute.cs delete mode 100644 Bunny.Common/Context/Database/TransactionInterceptor.cs create mode 100644 Bunny.Common/Filter/TransactionIAsyncActionFilter.cs diff --git a/Bunny.Common/Attribute/TransactionAttribute.cs b/Bunny.Common/Attribute/TransactionAttribute.cs new file mode 100644 index 0000000..0a01fc1 --- /dev/null +++ b/Bunny.Common/Attribute/TransactionAttribute.cs @@ -0,0 +1,6 @@ +namespace Bunny.Common.Attribute; + +[AttributeUsage(AttributeTargets.Method)] +public class TransactionAttribute : System.Attribute +{ +} \ No newline at end of file diff --git a/Bunny.Common/Context/Database/EFCoreContext.cs b/Bunny.Common/Context/Database/EFCoreContext.cs index 5b0e066..4a0af4f 100644 --- a/Bunny.Common/Context/Database/EFCoreContext.cs +++ b/Bunny.Common/Context/Database/EFCoreContext.cs @@ -37,7 +37,7 @@ public class EfCoreContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder options) { Log.Info("EfCoreContext 数据库连接..."); - options.UseSqlServer(DbPath).AddInterceptors(new TransactionInterceptor()); + options.UseSqlServer(DbPath); } /// diff --git a/Bunny.Common/Context/Database/TransactionInterceptor.cs b/Bunny.Common/Context/Database/TransactionInterceptor.cs deleted file mode 100644 index 9c3a68b..0000000 --- a/Bunny.Common/Context/Database/TransactionInterceptor.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Bunny.Common.Exception; -using Bunny.Dao.Common.Constant; -using Microsoft.EntityFrameworkCore.Diagnostics; - -namespace Bunny.Common.Context.Database; - -public class TransactionInterceptor : SaveChangesInterceptor -{ - // 重写 SavingChanges 方法 - public override InterceptionResult SavingChanges(DbContextEventData eventData, InterceptionResult result) - { - // 如果当前上下文存在事务,则直接返回结果 - if (eventData.Context!.Database.CurrentTransaction != null) return result; - - // 开始数据库事务 - using var transaction = eventData.Context.Database.BeginTransaction(); - try - { - // 调用基类方法继续保存更改 - result = base.SavingChanges(eventData, result); - - // 如果保存更改成功,则提交事务 - transaction.Commit(); - } - catch (System.Exception) - { - // 如果保存更改失败,则回滚事务并抛出自定义异常 - transaction.Rollback(); - throw new BunnyException(ExceptionConstant.DataBaseError); - } - - return result; - } -} \ No newline at end of file diff --git a/Bunny.Common/Filter/TransactionIAsyncActionFilter.cs b/Bunny.Common/Filter/TransactionIAsyncActionFilter.cs new file mode 100644 index 0000000..4cb11f2 --- /dev/null +++ b/Bunny.Common/Filter/TransactionIAsyncActionFilter.cs @@ -0,0 +1,39 @@ +using System.Transactions; +using Bunny.Common.Attribute; +using Bunny.Common.Context; +using log4net; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Filters; + +namespace Bunny.Common.Filter; + +public class TransactionIAsyncActionFilter : IAsyncActionFilter +{ + private static readonly ILog Log = LogManager.GetLogger(typeof(TransactionIAsyncActionFilter)); + + public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + var actionDesc = context.ActionDescriptor as ControllerActionDescriptor; + var hasNotTransactionalAttribute = + actionDesc?.MethodInfo.IsDefined(typeof(TransactionAttribute), false) ?? false; + + if (hasNotTransactionalAttribute) + { + await next(); + return; + } + + using var txScope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled); + var result = await next(); + if (result.Exception == null) + { + txScope.Complete(); + } + else + { + var errorMessage = + $"执行数据库出错 用户Id:[{BaseContext.GetUserId()}] token [{BaseContext.GetToken()}]:{result.Exception}"; + Log.Error(errorMessage); + } + } +} \ No newline at end of file diff --git a/Bunny.Service/IService/Service/BlogService.cs b/Bunny.Service/IService/Service/BlogService.cs index fada6d6..52d2155 100644 --- a/Bunny.Service/IService/Service/BlogService.cs +++ b/Bunny.Service/IService/Service/BlogService.cs @@ -1,4 +1,6 @@ -using Bunny.Common.Context.Database; +using Bunny.Common.Attribute; +using Bunny.Common.Context.Database; +using Bunny.Common.Exception; using Bunny.Common.Utils.Net; using Bunny.Dao.Common.Result; using Bunny.Dao.Dto.System; @@ -59,9 +61,9 @@ public class BlogService : IBlogService /// 批量添加数据 /// /// + [Transaction] public void AddBatchBlogs(string url) { - using var transaction = DbContext.Database.BeginTransaction(); var list = new List(); for (var i = 0; i <= 100; i++) @@ -69,7 +71,7 @@ public class BlogService : IBlogService DbContext.Blogs.AddRange(list); DbContext.SaveChanges(); - transaction.Commit(); + throw new BunnyException("测试事务注解"); } /// diff --git a/Bunny.WebApi/Configuration/ServiceRegistration.cs b/Bunny.WebApi/Configuration/ServiceRegistration.cs index 58dfa3d..8de2448 100644 --- a/Bunny.WebApi/Configuration/ServiceRegistration.cs +++ b/Bunny.WebApi/Configuration/ServiceRegistration.cs @@ -32,6 +32,7 @@ public static class ServiceRegistration { option.Filters.Add(); option.Filters.Add(); + option.Filters.Add(); option.Filters.Add(); }); } diff --git a/Bunny.WebApi/ReadMe/ReadMe.md b/Bunny.WebApi/ReadMe/ReadMe.md index 9f3ab02..a789827 100644 --- a/Bunny.WebApi/ReadMe/ReadMe.md +++ b/Bunny.WebApi/ReadMe/ReadMe.md @@ -371,4 +371,6 @@ Exception Filter(异常过滤器):用于处理应用程序中发生的异 7. TypeFilterAttribute 类似于ServiceFilterAttribute,但它是通过反射创建过滤器实例,不需要过滤器在DI容器中注册。 - 可以接受参数,用于构造过滤器实例。 \ No newline at end of file + 可以接受参数,用于构造过滤器实例。 + +![](https://learn.microsoft.com/zh-cn/aspnet/core/mvc/controllers/filters/_static/filter-pipeline-2.png?view=aspnetcore-8.0) \ No newline at end of file