【问题标题】:SQL Exception: "Impersonate Session Security Context" cannot be called in this batch because a simultaneous batch has called itSQL 异常:无法在此批处理中调用“模拟会话安全上下文”,因为同时批处理已调用它
【发布时间】:2010-03-30 13:24:30
【问题描述】:

从我们的 Web 应用程序打开到 SQL Server 2005 的连接时,我们偶尔会看到以下错误:

“模拟会话安全上下文”无法在此批处理中调用,因为同时批处理已调用它。

我们使用 MARS 和连接池。

异常源自以下代码:

protected SqlConnection Open()
{
    SqlConnection connection = new SqlConnection();
    connection.ConnectionString = m_ConnectionString;
    if (connection != null)
    {
        try
        {
            connection.Open();
            if (m_ExecuteAsUserName != null)
            {
                string sql = Format("EXECUTE AS LOGIN = {0};", m_ExecuteAsUserName);
                ExecuteCommand(connection, sql);
            }
        }
        catch (Exception exception)
        {
            connection.Close();
            connection = null;
        }
    }
    return connection;
}

我发现了一个MS Connect article,这表明该错误是由于在发送 EXECUTE AS LOGIN 命令之前之前的命令尚未终止时引起的。然而,如果连接刚刚打开,这怎么可能呢?

这可能与连接池与 MARS 的奇怪交互有关吗?

更新:在短期内,我们实施了一种解决方法,即在发生这种情况时清除连接池,以摆脱不良连接,否则它会不断交还给不同的用户。 (现在这种情况每天会发生 5-10 次,同时只有少数同时用户,所以这很烦人。)但如果有人有任何进一步的想法,我们仍在寻找真正的解决方案......

【问题讨论】:

    标签: c# asp.net sql-server-2005 connection-pooling sql-server-mars


    【解决方案1】:

    我会说这是 MARS 而不是池

    来自“Using Multiple Active Result Sets (MARS)

    • 应用程序可以有多个默认值 结果集打开并且可以交错 从他们那里阅读。
    • 应用程序可以 执行其他语句(例如, 插入、更新、删除和存储 过程调用)而默认结果 集是开放的。

    基本形式的连接池意味着连接打开/关闭的开销被最小化,但任何连接(直到 MARS)在任何时候都会发生一件事。池化已经存在了一段时间,而且开箱即用。

    MARS(顺便说一句我没用过)为任何单个连接引入了重叠的“东西”。所以可能是 MARS 而不是连接池是 2 的更大罪魁祸首。

    来自“Extending Database Impersonation by Using EXECUTE AS

    当通过以下方式冒充委托人时 使用 EXECUTE AS LOGIN 语句, 或在服务器范围的模块中 使用 EXECUTE AS 子句,范围 的模拟是服务器范围的。

    这可以解释 MARS 导致它的原因:2 个会话中的相同主体都运行 EXECUTE AS。 那篇使用中可能有什么,或者试试这个:

    IF ORIGINAL_LOGIN() = SUSER_SNAME() EXECUTE AS LOGIN = {0};
    

    经过反思并阅读此答案后,我不认为尝试在一个连接中更改每个会话 (MARS) 的执行上下文是一个好主意...

    【讨论】:

    • 感谢您的回复。我同意它一定与 MARS 有关,但多个结果集肯定是基于每个连接的吗?而且我的连接没有任何以前的结果集,因为我刚刚打开它并且它是“新的”(尽管来自池)。我认为在你的第二个引用中说“模拟的范围是服务器范围的”,这意味着仅适用于当前连接。
    • @kasey:我的猜测是单个连接有很多会话,而 EXECUTE AS 是每个会话。当从池中重新使用连接时,我猜上下文切换仍然设置。嗯。也许这只是连接池和 EXECUTE AS... 您在这里遇到的有趣问题 :-)
    【解决方案2】:

    不要责怪连接池 - MARS 因造成严重破坏而臭名昭著。 不完全是它的责任,但它是一半一半。要记住的关键是 MARS 是经过设计的,并且仅适用于“正常”数据库使用(意思是,常规 CRUD 内容没有管理批处理)。任何对 DB 引擎有广泛影响的命令都可能触发 MARS,即使它只是一个连接和单线程(例如运行设置批处理来创建表或嵌套事务)。

    话虽如此,人们可以很容易地责怪 MARS,但它对于 99% 左右的正常 CRUD 场景(以及像 ORM-s 和 LINQ 等低效率的东西终生依赖它)来说非常有效。这意味着人们必须了解,如果他们想通过连接破解 SQL,他们就不能使用 MARS。例如,我有一个从头开始创建整个数据库的设置代码,因为它非常便于部署,但它与正在部署的 Web 服务共享连接刺痛 - 哎呀 :-) 我花了几天时间挖掘来学习我的课程.所以我只是保持关注点的分离(这总是好的),问题就消失了。

    【讨论】:

      【解决方案3】:

      您是否尝试在 sql 语句的末尾使用 revert?

      http://msdn.microsoft.com/en-us/library/ms178632.aspx

      我总是这样做只是为了确保当前上下文恢复正常。

      【讨论】:

      • 好主意,但是是的 - 我们有 try/catch 块来确保我们这样做,而且如果你忘记这样做,你会得到不同类型的错误(由 SQL 记录的“严重错误”服务器也是)。
      猜你喜欢
      • 2013-02-12
      • 1970-01-01
      • 1970-01-01
      • 2010-10-12
      • 1970-01-01
      • 1970-01-01
      • 2013-03-01
      • 1970-01-01
      • 2014-09-04
      相关资源
      最近更新 更多