.NET Framework4.5事务多连接偶发不支持错误仅生产环境复现求助
问题根因
该错误的触发原因和你代码的DbContext生命周期管理逻辑直接相关,本地测试无压力不会复现,生产环境高并发下偶发的原因如下:
- 你的
Repository每次实例化都会新建一个SampleContext,同一事务范围内如果存在多个DbContext实例,就算连接字符串完全一致,高并发场景下数据库连接池大概率不会复用同一个物理连接,导致事务内出现多个独立连接,触发报错。 - 你虽然给
Repository实现了IDisposable接口,但业务代码中没有对Repository实例进行主动释放,DbContext占用的数据库连接无法及时归还到连接池,进一步提升了连接池分配新连接的概率。 - 代码中存在不规范写法加剧了问题:
throw ex会清空原始异常调用栈,不利于问题排查;Repository构造函数你写为private,属于简化代码的笔误,实际运行时应该为public否则无法实例化。
解决方案
快速修复(代码改动最小,可快速验证效果)
- 所有用到
Repository的地方统一用using块包裹,强制DbContext及时释放,归还数据库连接:
public class Business { public List<Item> GetList() { using(var dao = new Repository()) { return dao.GetList().ToList(); } } public void Update(string id) { try { using(var dao = new Repository()) { var item = dao.Get(id); item.UpdateDate = DateTime.Now; dao.Update(item); } } catch (Exception ex) { // 不要用throw ex,直接throw保留原始异常栈 throw; } } }
- 给
TransactionScope添加事务配置,提升轻量级事务的兼容性:
using (var ts = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }, TransactionScopeAsyncFlowOption.Enabled)) { business.Update(id); ts.Complete(); }
- 可在数据库连接字符串中适当调大连接池上限,比如添加参数
Max Pool Size=200,降低高并发下分配新连接的概率。
根本修复(彻底解决该类问题)
整个请求生命周期内复用同一个DbContext实例,不要每次数据库操作都新建DbContext:
- 用依赖注入框架(比如Autofac、Unity,ASP.NET MVC 5也自带简易DI)配置
SampleContext的生命周期为PerRequest,每个请求仅初始化一次SampleContext。 - 所有
Repository的构造函数直接注入当前请求的SampleContext,不再自己新建上下文。
修改完成后,整个请求的所有数据库操作都复用同一个连接,完全不会出现事务内多连接的情况,从根源上避免该错误。
额外优化建议
你提前提交事务的逻辑是合理的,不需要调整,另外注意补全代码中遗漏的result变量定义,该变量在你贴的代码中未声明就使用。
内容的提问来源于stack exchange,提问作者kisetu
相关产品推荐
相关产品推荐

