其实这个错误跟LINQ To Sql没有必然的关系, 不过我觉得见到它的场景一般情况下都应该是用LINQ的时候.

以下示例代码:

 1            try
 2            {
 3                dc.SubmitChanges();
 4                dc.sp1();
 5                tran.Commit();
 6            }

 7            catch (Exception ex)
 8            {
 9                tran.Rollback();
10                Master.SetError(ex.Message);
11                return;
12            }

如果在try块的前面dc上有select 动作, 并且存储过程sp1 中也有select动作, 则上述语句将抛出异常:
There is already an open DataReader associated with this Command which must be closed first

经过单步跟踪, 第一次是tran.Commit 先抛出异常, 被catch块捕捉, 执行tran.Rollback时再次抛出异常, 这里没有捕捉器了,整个程序于是异常. 如果仅仅是异常还算好事了, 由于LINQ 事务操作的时候, 是用排它锁锁定目标表的, 所以事务没有结束, 目标表就一直被锁定, 这里由于事务既无法提交也无法回滚, 所以目标表被锁死.

看得出这个错误是毁灭性的.
究其原因, 是因为默认情况下, 不允许返回多个dataSet, 如果不用LINQ的话, 我想基本上也不会需要返回多个dataset, 所以应该很少会碰到这个错误, 但是用linq的话,概率就很大了. 解决办法:
1. 不要在存储过程中返回结果集.(貌似不太现实...)
2. 给连接字符串加上"MultipleActiveResultSets=True"

如果表已经被锁死, 解决办法:
1. 重启SQL SERVER 服务
2. 先在查询分析器上按ctrl+2 , 返回当前锁定的情况. 例如:

spid dbid ObjId IndId Type Resource Mode Status
51   5      0      0       DB                   X      GRANT

找到Mode 带"X"的项的spid, 例如上面一行, spid是51, 在查询分析器中执行: KILL 51

 

感觉不可理解的是为什么事务回滚也会抛出异常, 使得这个错误一旦发生后果就极其严重, 无论是何种初衷禁止返回多个结果集, 都不应该让表这样被锁死, 鄙视一下微软...

posted on 2009-03-23 12:10  夏狼哉  阅读(1036)  评论(0编辑  收藏  举报