使用多个活动结果集(MARS)

SQL Server 2005 在访问数据库引擎的应用程序中引入了对多个活动结果集(MARS)的支持。 在早期版本的 SQL Server 中,数据库应用程序无法在连接上维护多个活动语句。 使用 SQL Server 默认结果集时,应用程序必须处理或取消一个批处理中的所有结果集,然后才能在该连接上执行任何其他批处理。 SQL Server 2005 引入了一个新的连接属性,允许应用程序为每个连接具有多个挂起的请求,特别是每个连接具有多个活动默认结果集。

MARS 通过以下新功能简化了应用程序设计:

  • 应用程序可以打开多个默认结果集,并且可以交错读取它们。

  • 应用程序可以在打开默认结果集时执行其他语句(例如 INSERT、UPDATE、DELETE 和存储过程调用)。

使用 MARS 的应用程序将找到以下有益指南:

  • 默认结果集应用于单个 SQL 语句生成的短生存期或短结果集(SELECT、DML 和 OUTPUT、RECEIVE、READ TEXT 等)。

  • 服务器游标应用于由单个 SQL 语句生成的较长生存期或大型结果集。

  • 无论结果是否返回结果,以及返回多个结果的批处理,始终读取到过程请求的结果的末尾。

  • 尽可能使用 API 调用来更改连接属性并优先管理事务,而不是 Transact-SQL 语句。

  • 在 MARS 中,并发批处理运行时禁止会话范围的模拟。

注释

默认情况下,未启用 MARS 功能。 若要使用 SQL Server Native Client 连接到 SQL Server 时使用 MARS,必须在连接字符串中专门启用它。 有关详细信息,请参阅本主题后面的 SQL Server Native Client OLE DB 提供程序和 SQL Server Native Client ODBC 驱动程序部分。

SQL Server Native Client 不会限制连接上的活动语句数。

不需要同时执行的单个多语句批处理或存储过程的典型应用程序将受益于 MARS,而无需了解 MARS 的实现方式。 但是,具有更复杂的要求的应用程序确实需要考虑到这一点。

MARS 允许在单个连接内交错执行多个请求。 也就是说,它允许批处理运行,并在其执行中允许执行其他请求。 但是,请注意,MARS 是在交错(而不是并行执行方面)定义的。

MARS 基础结构允许多个批处理以交错方式执行,但只能在定义良好的点切换执行。 此外,大多数语句必须在批处理中以原子方式运行。 向客户端返回行的语句(有时称为 生成点)允许在完成之前交错执行,而将行发送到客户端,例如:

  • 选择

  • 获取

  • 收到

作为存储过程或批处理的一部分执行的任何其他语句都必须运行到完成,然后才能将执行切换到其他 MARS 请求。

批处理交错执行的确切方式受多种因素的影响,很难预测将执行包含生成点的多个批处理中的命令的确切顺序。 请小心避免由于此类复杂批处理的交错执行而产生不必要的副作用。

通过使用 API 调用而不是 Transact-SQL 语句来管理连接状态(SET、USE)和事务(BEGIN TRAN、COMMIT、ROLLBACK)时避免问题,方法是在包含生成点的多语句批处理中不包括这些语句,并通过使用或取消所有结果序列化此类批处理的执行。

注释

启用 MARS 时启动手动或隐式事务的批处理或存储过程必须在批处理退出之前完成事务。 否则,SQL Server 会在批处理完成后回滚事务所做的所有更改。 此类事务由 SQL Server 作为批处理范围的事务进行管理。 这是 SQL Server 2005 中引入的一种新型事务,用于启用 MARS 时要使用的现有行为良好的存储过程。 有关批处理范围的事务的详细信息,请参阅 Transaction Statements (Transact-SQL)

有关从 ADO 使用 MARS 的示例,请参阅 将 ADO 与 SQL Server Native Client 配合使用

SQL Server Native Client OLE DB 访问接口

SQL Server Native Client OLE DB 访问接口通过添加SSPROP_INIT_MARSCONNECTION数据源初始化属性(在DBPROPSET_SQLSERVERDBINIT属性集中实现)支持 MARS。 此外,还添加了新的连接字符串关键字 MarsConn。 它接受 truefalse 值; false 是默认值。

数据源属性DBPROP_MULTIPLECONNECTIONS默认为VARIANT_TRUE。 这意味着提供程序将生成多个连接,以支持多个并发命令和行集对象。 启用 MARS 后,SQL Server Native Client 可以在单个连接上支持多个命令和行集对象,因此默认情况下,MULTIPLE_CONNECTIONS设置为VARIANT_FALSE。

有关DBPROPSET_SQLSERVERDBINIT属性集的增强功能的详细信息,请参阅 初始化和授权属性

SQL Server Native Client OLE DB 提供程序示例

在此示例中,数据源对象是使用 SQL Server Native OLE DB 访问接口创建的,在创建会话对象之前使用DBPROPSET_SQLSERVERDBINIT属性集启用 MARS。

#include <sqlncli.h>  
  
IDBInitialize *pIDBInitialize = NULL;  
IDBCreateSession *pIDBCreateSession = NULL;  
IDBProperties *pIDBProperties = NULL;  
  
// Create the data source object.  
hr = CoCreateInstance(CLSID_SQLNCLI10, NULL,  
   CLSCTX_INPROC_SERVER,  
   IID_IDBInitialize,   
    (void**)&pIDBInitialize);  
  
hr = pIDBInitialize->QueryInterface(IID_IDBProperties, (void**)&pIDBProperties);  
  
// Set the MARS property.  
DBPROP rgPropMARS;  
  
// The following is necessary since MARS is off by default.  
rgPropMARS.dwPropertyID = SSPROP_INIT_MARSCONNECTION;  
rgPropMARS.dwOptions = DBPROPOPTIONS_REQUIRED;  
rgPropMARS.dwStatus = DBPROPSTATUS_OK;  
rgPropMARS.colid = DB_NULLID;  
V_VT(&(rgPropMARS.vValue)) = VT_BOOL;  
V_BOOL(&(rgPropMARS.vValue)) = VARIANT_TRUE;  
  
// Create the structure containing the properties.  
DBPROPSET PropSet;  
PropSet.rgProperties = &rgPropMARS;  
PropSet.cProperties = 1;  
PropSet.guidPropertySet = DBPROPSET_SQLSERVERDBINIT;  
  
// Get an IDBProperties pointer and set the initialization properties.  
pIDBProperties->SetProperties(1, &PropSet);  
pIDBProperties->Release();  
  
// Initialize the data source object.  
hr = pIDBInitialize->Initialize();  
  
//Create a session object from a data source object.  
IOpenRowset * pIOpenRowset = NULL;  
hr = IDBInitialize->QueryInterface(IID_IDBCreateSession, (void**)&pIDBCreateSession));  
hr = pIDBCreateSession->CreateSession(  
   NULL,             // pUnkOuter  
   IID_IOpenRowset,  // riid  
  &pIOpenRowset ));  // ppSession  
  
// Create a rowset with a firehose mode cursor.  
IRowset *pIRowset = NULL;  
DBPROP rgRowsetProperties[2];  
  
// To get a firehose mode cursor request a   
// forward only read only rowset.  
rgRowsetProperties[0].dwPropertyID = DBPROP_IRowsetLocate;  
rgRowsetProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED;  
rgRowsetProperties[0].dwStatus = DBPROPSTATUS_OK;  
rgRowsetProperties[0].colid = DB_NULLID;  
VariantInit(&(rgRowsetProperties[0].vValue));  
rgRowsetProperties[0].vValue.vt = VARIANT_BOOL;  
rgRowsetProperties[0].vValue.boolVal = VARIANT_FALSE;  
  
rgRowsetProperties[1].dwPropertyID = DBPROP_IRowsetChange;  
rgRowsetProperties[1].dwOptions = DBPROPOPTIONS_REQUIRED;  
rgRowsetProperties[1].dwStatus = DBPROPSTATUS_OK;  
rgRowsetProperties[1].colid = DB_NULLID;  
VariantInit(&(rgRowsetProperties[1].vValue));  
rgRowsetProperties[1].vValue.vt = VARIANT_BOOL;  
rgRowsetProperties[1].vValue.boolVal = VARIANT_FALSE;  
  
DBPROPSET rgRowsetPropSet[1];  
rgRowsetPropSet[0].rgProperties = rgRowsetProperties  
rgRowsetPropSet[0].cProperties = 2  
rgRowsetPropSet[0].guidPropertySet = DBPROPSET_ROWSET;  
  
hr = pIOpenRowset->OpenRowset (NULL,  
   &TableID,  
   NULL,  
   IID_IRowset,  
   1,  
   rgRowsetPropSet  
   (IUnknown**)&pIRowset);  

SQL Server Native Client ODBC 驱动程序

SQL Server Native Client ODBC 驱动程序通过添加 SQLSetConnectAttrSQLGetConnectAttr 函数支持 MARS。 已添加SQL_COPT_SS_MARS_ENABLED以接受SQL_MARS_ENABLED_YES或SQL_MARS_ENABLED_NO,SQL_MARS_ENABLED_NO为默认值。 此外,还添加了新的连接字符串关键字 Mars_Connection。 它接受“是”或“否”值;“no”是默认值。

SQL Server Native Client ODBC 驱动程序示例

在此示例中, SQLSetConnectAttr 函数用于在调用 SQLDriverConnect 函数连接数据库之前启用 MARS。 建立连接后,将调用两个 SQLExecDirect 函数,以在同一连接上创建两个单独的结果集。

#include <sqlncli.h>  
  
SQLSetConnectAttr(hdbc, SQL_COPT_SS_MARS_ENABLED, SQL_MARS_ENABLED_YES, SQL_IS_UINTEGER);  
SQLDriverConnect(hdbc, hwnd,   
   "DRIVER=SQL Server Native Client 10.0;  
   SERVER=(local);trusted_connection=yes;", SQL_NTS, szOutConn,   
   MAX_CONN_OUT, &cbOutConn, SQL_DRIVER_COMPLETE);  
  
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt1);  
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt2);  
  
// The 2nd execute would have failed with connection busy error if  
// MARS were not enabled.  
SQLExecDirect(hstmt1, L"SELECT * FROM Authors", SQL_NTS);  
SQLExecDirect(hstmt2, L"SELECT * FROM Titles", SQL_NTS);  
  
// Result set processing can interleave.  
SQLFetch(hstmt1);  
SQLFetch(hstmt2);  

另请参阅

SQL Server Native Client 功能
使用 SQL Server 默认结果集