.NET Core依赖注入DbContext快速连续点击报线程冲突错误如何解决
问题根因
静态实例共享DbContext触发并发冲突
你在RGWIncrementUserActionClicks类中定义了static readonly IncrementSiteActions _IncrementSiteActions、static readonly IncrementUserActions _IncrementUserActions两个静态实例。从报错栈可以看出,IncrementUserActions内部持有独立的DbContext成员,静态实例的生命周期和应用进程一致,这就导致所有请求共用同一个DbContext实例,多请求并发操作时直接触发EF Core的线程安全校验错误。
你之前的理解误区是认为await会阻塞后续请求,实际上ASP.NET Core是多线程并发处理请求的,每个请求都是独立线程执行,await只能保证单个请求内部的执行顺序,不会阻止服务器处理新的请求,多个请求同时操作静态实例持有的同一个DbContext必然报错。前端重复提交触发多请求
快速连续点击按钮会生成多个独立的HTTP请求,就算修复了DbContext的问题,也会出现重复计数的业务逻辑错误。
修复方案
1. 修正依赖注入逻辑,移除静态实例
所有用到DbContext的业务类都不要使用静态实例,改为注入到DI容器走Scoped生命周期(每个请求一个独立实例):
- 删除
RGWIncrementUserActionClicks、IncrementSiteActions、IncrementUserActions类中的静态实例声明 - 在Startup.cs中注册三个业务类:
services.AddScoped<RGWIncrementUserActionClicks>(); services.AddScoped<IncrementSiteActions>(); services.AddScoped<IncrementUserActions>();
- 控制器不再自行new
RGWIncrementUserActionClicks,改为构造函数注入:
private readonly RGWIncrementUserActionClicks _rgwIncrementClicks; private readonly ApplicationDbContext _context; public RGWController(IEmailSender emailSender, ApplicationDbContext context, RGWIncrementUserActionClicks rgwIncrementClicks) { _emailSender = emailSender; _context = context; _rgwIncrementClicks = rgwIncrementClicks; }
IncrementSiteActions和IncrementUserActions类改为构造函数注入ApplicationDbContext,不要自行持有静态的DbContext成员。- 建议统一SaveChanges调用时机:当前逻辑里
IncrementUserActions内部调用一次SaveChangesAsync,UserClick末尾又调用一次,会导致事务拆分,整个业务逻辑执行完统一调用一次即可。
2. 前端增加防重复点击逻辑
点击按钮后立即禁用按钮,等页面跳转后自动重置,从入口避免重复请求,示例代码:
document.querySelector('#click-button').addEventListener('click', function() { this.disabled = true; });
内容的提问来源于stack exchange,提问作者DMur
相关产品推荐
相关产品推荐

