在事务内调用WCF方法出现超时错误,问题出在哪里?
问题描述
我有一个复杂应用,运行时出现错误,现将问题简化为以下代码场景:
WCF服务查询方法
public string FindDocumentNumber(int documentId) { using(var context = new MyDbContext()) { return context.Documents.Where(x=>x.Id == documentId && x.Tag == "*") .Select(x=>x.Number).FirstOrDefault(); } }
控制台应用调用代码
using(var scope = new TransactionScope()) { using(var context = new MyDbContext()) { var doc = context.Documents.Where(x=>x.Id == 12345).FirstOrDefault(); doc.Tag = "*"; context.SaveChange(); } ... var number = myWCFService.FindDocumentNumber(12345); // 此处触发错误 ... //对ID为12345的文档执行其他更新操作 scope.Complete(); }
运行时错误信息
System.Data.Entity.Core.EntityCommandExecutionException
HResult=0x8013193C Message=执行命令定义时出错。有关详细信息,请参阅内部异常。
Source= StackTrace:Inner Exception 1: SqlException: 执行超时已过期。操作完成前超时时间已过或服务器未响应。
Inner Exception 2: Win32Exception: 等待操作超时
请问问题出在哪里?
问题原因及解决方案
核心原因
控制台应用中开启的TransactionScope事务未完成(未调用scope.Complete())时,事务内更新的ID为12345的文档会被数据库加上排他锁。WCF服务的FindDocumentNumber方法发起新查询时,尝试读取这条被锁定的记录,而SQL Server默认的可重复读隔离级别下,未提交修改的排他锁会阻塞其他事务的读操作,导致查询无限等待锁释放,最终触发超时。
解决方案
- 调整事务范围:若WCF查询无需纳入控制台事务,可将查询代码移到
TransactionScope外;或拆分事务,在调用WCF方法前完成当前事务(需确保业务逻辑允许拆分)。 - 降低事务隔离级别:创建
TransactionScope时指定更低的隔离级别,比如ReadCommitted(避免未提交读的脏数据问题,同时允许读取已提交的修改):
var transactionOptions = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }; using(var scope = new TransactionScope(TransactionScopeOption.Required, transactionOptions)) { // 原有业务代码 }
- 优化锁等待逻辑:确保查询使用主键+索引字段,缩短锁持有时间;或调整业务流程,将更新操作与查询操作的时序重新安排,避免锁冲突。
内容的提问来源于stack exchange,提问作者Masoud
相关产品推荐
相关产品推荐

