文章目录
- 前言
- 一、自动事务的ActionFilter
- 二、使用步骤
-
- 1)创建事务控制标注特性
- 2)实现事务过滤器
- [3)注册过滤器和 DbContext](#3)注册过滤器和 DbContext)
- 4)使用标注控制事务
- 三、关键机制说明
- 四、扩展场景
- 总结
前言
一、自动事务的ActionFilter
ActionFilter是用于在控制器动作执行前后插入逻辑的,要实现自动事务,应该是在OnActionExecuting开始事务,在OnActionExecuted根据结果提交或回滚。
二、使用步骤
1)创建事务控制标注特性
-
定义一个 [Transactional ] 特性,用于标记需要启用事务的 Controller 或 Action
bashusing System.Data; [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)] public class TransactionalAttribute : Attribute { // 可选:扩展属性,例如隔离级别 public IsolationLevel IsolationLevel { get; set; } = IsolationLevel.ReadCommitted; }
2)实现事务过滤器
-
创建一个支持事务自动管理的 Action Filter ,并根据 [Transactional ] 标注决定是否启用事务
bashusing System.Data; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.EntityFrameworkCore; using InfrastructureLibrary.Data; public class TransactionFilter : IAsyncActionFilter { private readonly MyDbContext _dbContext; public TransactionFilter(MyDbContext dbContext) { _dbContext = dbContext; } public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { var (isTransactional, isolationLevel) = CheckTransactionAttribute(context); if (!isTransactional) { await next(); return; } await using var transaction= await _dbContext.Database.BeginTransactionAsync(isolationLevel); try { var res = await next(); if (res.Exception != null) { await transaction.RollbackAsync(); } else { await transaction.CommitAsync(); } } catch (Exception) { await transaction.RollbackAsync(); throw; } } private (bool IsTransactional, IsolationLevel IsolationLevel) CheckTransactionAttribute(ActionExecutingContext context) { var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor; if (actionDescriptor == null) return (false, default); var attribute = actionDescriptor.MethodInfo .GetCustomAttributes(typeof(TransactionalAttribute), true) .Cast<TransactionalAttribute>() .FirstOrDefault() ??actionDescriptor.ControllerTypeInfo.GetCustomAttributes(typeof(TransactionalAttribute),true) .Cast<TransactionalAttribute>() .FirstOrDefault(); return (attribute != null, attribute?.IsolationLevel ?? IsolationLevel.ReadCommitted); } }
3)注册过滤器和 DbContext
-
注册过滤器
bashbuilder.Services.AddControllers(opt => { opt.Filters.Add<TransactionFilter>(); });
-
注册DbContext
bashbuilder.Services.AddDbContext<MyDbContext>(opt => { string connStr = builder.Configuration.GetConnectionString("DefaultConnection"); opt.UseSqlServer(connStr); });
4)使用标注控制事务
-
在需要事务的 Controller 或 Action 上添加 [Transactional ] 特性。
bash[Route("api/[controller]/[action]")] [ApiController] [Transactional] public class TestFilterController : ControllerBase { private readonly IBookRepository _bookRepository; private readonly IPersonRepository _personRepository; public TestFilterController(IBookRepository bookRepository, IPersonRepository personRepository) { _bookRepository = bookRepository; _personRepository = personRepository; } [HttpPost] //[Transactional] [Transactional(IsolationLevel =IsolationLevel.Serializable)]//方法级别自定义隔离级别 public async Task<IActionResult> TestAdd() { await _bookRepository.AddAsync(new Book { Author="33", Title="44",Price=30}); await _personRepository.AddAsync(new Person { Name = "gggggggggggg", Age = 20 }); return Ok(); } [HttpGet] public ActionResult<string> Test() { Console.WriteLine("Action执行中"); var res = System.IO.File.ReadAllText("d:/asdf.txt"); return res; } }
三、关键机制说明
-
标注驱动
通过 [Transactional] 特性标记需要事务的方法或控制器,过滤器自动检测并开启事务。
-
作用域与生命周期
TransactionFilter 注册为 Scoped ,确保每个请求有独立的事务。
DbContext 默认注册为 Scoped,与事务生命周期一致。 -
隔离级别配置
可通过 [Transactional(IsolationLevel = ...)] 指定事务隔离级别。
-
查询操作(低隔离 ):可能使用 ReadCommitted(默认),允许较高的并发性。
-
资金转账(高隔离 ):可能使用 Serializable,严格避免脏读、不可重复读、幻读。
-
批量导入(自定义 ):可能选择 RepeatableRead,平衡性能和一致性。
-
常见隔离级别及其行为
隔离级别 允许的并发问题 适用场景 ReadUncommitted 允许脏读、不可重复读、幻读 对性能要求极高,可接受数据不一致 ReadCommitted (默认) 防止脏读,允许不可重复读、幻读 多数业务场景(如普通查询和更新) RepeatableRead 防止脏读、不可重复读,允许幻读 需要保证同一事务内多次读取结果一致 Serializable 防止所有并发问题(最高隔离,性能最低) 资金操作、严格一致性要求(如库存扣减)
-
-
异常处理
Action 执行异常时自动回滚事务。未标记 [Transactional] 的请求直接跳过事务逻辑。
四、扩展场景
-
多数据库支持
注入多个 DbContext 并在事务中协调(需要分布式事务支持)。
-
自定义过滤逻辑
在 CheckTransactionalAttribute 中添加更复杂的判断逻辑(如基于用户角色)。
-
与现有过滤器集成
通过 Order 属性控制过滤器的执行顺序。
总结
通过此方案,开发者可以灵活控制事务的启用和配置,同时保持代码简洁性和数据一致性。