【问题标题】:Force SQL Server to close result sets on DML queries强制 SQL Server 关闭 DML 查询的结果集
【发布时间】:2019-12-10 15:20:35
【问题描述】:

我有一个 PHP 程序,它使用 PDO::sqlsrv 驱动程序来查询 MS SQL Server 数据库。

这有一些奇怪的行为。如果我启用了 MARS (https://docs.microsoft.com/en-us/sql/relational-databases/native-client/features/using-multiple-active-result-sets-mars?view=sql-server-ver15),这是默认设置,并尝试在某些时候启动事务,我会收到以下错误:

["42000",3988,"[Microsoft][ODBC Driver 17 for SQL Server][SQL Server]New transaction is not allowed because there are other threads running in the session."]

这似乎是因为一些活动的结果集需要关闭。不幸的是,我不知道如何确定会话中正在运行哪些线程。我关闭了 MARS 以尝试更好地确定哪些查询没有正确关闭,并且在任何插入/更新后我收到以下错误:

IMSSP
-61
The connection cannot process this operation because there is a statement with pending results.  To make the connection available for other queries, either fetch all results or cancel or free the statement.  For more information, see the product documentation about the MultipleActiveResultSets connection option.

显然任何插入/更新都会创建一个需要关闭其游标的结果集。

在每个 DML 语句修复问题后手动关闭游标。这很不方便,而且似乎不应该是 SQL Server 的行为来创建无意义的结果集(DML 语句不返回任何行)。

这是预期的行为(DML 语句需要手动关闭关联的游标)吗?

有没有办法阻止这种行为(DML 语句自动关闭游标)?

有没有办法关闭连接上所有打开的结果集,以便我可以启动事务(这很容易实现)?

【问题讨论】:

  • 看来您应该在此处发布您的 PHP 代码并对其进行标记,以便我们了解您正确处理连接的原因,
  • DML 不创建结果集,除非是 OUTPUT 子句,或者触发器返回结果集。您将收到 DONE_IN_PROC 消息,除非您 SET NOCOUNT ON,并且某些客户端堆栈不会自动处理 DONE_IN_PROC 消息。
  • @DavidBrowne-Microsoft 尝试从结果语句中获取任何内容不会返回任何内容;但似乎结果上有一个打开的光标(直到它被手动关闭)。
  • 可能是这样,具体取决于客户端驱动程序的实现方式。

标签: sql-server tsql pdo sqlsrv


【解决方案1】:

关闭ResultSet 非常简单。首先我要提一下,即使 MARS 被禁用,两个 ResultSets 也可以一起使用,但有限制。

当使用PDO_SQLSRV 时,使用方法ResultSet::current() 放置一个服务器端指针CURSOR 以记住当前行。因此,您可以稍后在代码中继续迭代。如果此CURSOR 放置在服务器端,您将无法使用第二个ResultSet

方法

取消设置结果集

/* e.g. get first row of first resultset */
$result = $resultSet1->current();

unset($resultSet1);

/* e.g. get first row of second resultset */
$anotherResult = $resultSet2->current();

倒回光标

/* e.g. get first row of first resultset */
$result = $resultSet1->current();

$resultSet1->rewind();

/* e.g. get first row of second resultset */
$anotherResult = $resultSet2->current();

循环遍历结果集

/* e.g. get first row of first resultset */
$result = null;
foreach ($resultSet1 as $row) {
    $result = $row;
    break;
}

/* e.g. do something with second resultset */
foreach ($resultSet2 as $row) {
    /* do something with $row */
}

客户端游标

您还可以设置 PDO 选项以使用客户端游标。因此完整的结果将被放入 RAM 中,并在其中模拟光标。

https://docs.microsoft.com/en-us/sql/connect/php/cursor-types-sqlsrv-driver?view=sql-server-ver15#client-side-cursors-and-the-sqlsrv-driver

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-09-19
    • 2015-02-16
    • 1970-01-01
    • 2016-05-17
    • 1970-01-01
    • 2013-03-27
    • 1970-01-01
    • 2018-07-25
    相关资源
    最近更新 更多