♻️ feat(新增): 添加方法上的事务注解
This commit is contained in:
parent
18e6c9adbf
commit
0039f37f8d
|
@ -0,0 +1,6 @@
|
||||||
|
namespace Bunny.Common.Attribute;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Method)]
|
||||||
|
public class TransactionAttribute : System.Attribute
|
||||||
|
{
|
||||||
|
}
|
|
@ -37,7 +37,7 @@ public class EfCoreContext : DbContext
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder options)
|
protected override void OnConfiguring(DbContextOptionsBuilder options)
|
||||||
{
|
{
|
||||||
Log.Info("EfCoreContext 数据库连接...");
|
Log.Info("EfCoreContext 数据库连接...");
|
||||||
options.UseSqlServer(DbPath).AddInterceptors(new TransactionInterceptor());
|
options.UseSqlServer(DbPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -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<int> SavingChanges(DbContextEventData eventData, InterceptionResult<int> 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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.Common.Utils.Net;
|
||||||
using Bunny.Dao.Common.Result;
|
using Bunny.Dao.Common.Result;
|
||||||
using Bunny.Dao.Dto.System;
|
using Bunny.Dao.Dto.System;
|
||||||
|
@ -59,9 +61,9 @@ public class BlogService : IBlogService
|
||||||
/// 批量添加数据
|
/// 批量添加数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="url"></param>
|
/// <param name="url"></param>
|
||||||
|
[Transaction]
|
||||||
public void AddBatchBlogs(string url)
|
public void AddBatchBlogs(string url)
|
||||||
{
|
{
|
||||||
using var transaction = DbContext.Database.BeginTransaction();
|
|
||||||
var list = new List<Blog>();
|
var list = new List<Blog>();
|
||||||
|
|
||||||
for (var i = 0; i <= 100; i++)
|
for (var i = 0; i <= 100; i++)
|
||||||
|
@ -69,7 +71,7 @@ public class BlogService : IBlogService
|
||||||
|
|
||||||
DbContext.Blogs.AddRange(list);
|
DbContext.Blogs.AddRange(list);
|
||||||
DbContext.SaveChanges();
|
DbContext.SaveChanges();
|
||||||
transaction.Commit();
|
throw new BunnyException("测试事务注解");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -32,6 +32,7 @@ public static class ServiceRegistration
|
||||||
{
|
{
|
||||||
option.Filters.Add<GlobalExceptionFilter>();
|
option.Filters.Add<GlobalExceptionFilter>();
|
||||||
option.Filters.Add<ValidateModelStateAttribute>();
|
option.Filters.Add<ValidateModelStateAttribute>();
|
||||||
|
option.Filters.Add<TransactionIAsyncActionFilter>();
|
||||||
option.Filters.Add<AuthorizationFilter>();
|
option.Filters.Add<AuthorizationFilter>();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -372,3 +372,5 @@ Exception Filter(异常过滤器):用于处理应用程序中发生的异
|
||||||
7. TypeFilterAttribute
|
7. TypeFilterAttribute
|
||||||
类似于ServiceFilterAttribute,但它是通过反射创建过滤器实例,不需要过滤器在DI容器中注册。
|
类似于ServiceFilterAttribute,但它是通过反射创建过滤器实例,不需要过滤器在DI容器中注册。
|
||||||
可以接受参数,用于构造过滤器实例。
|
可以接受参数,用于构造过滤器实例。
|
||||||
|
|
||||||
|
![](https://learn.microsoft.com/zh-cn/aspnet/core/mvc/controllers/filters/_static/filter-pipeline-2.png?view=aspnetcore-8.0)
|
Loading…
Reference in New Issue