使用多个活动的结果集 (MARS)
SQL Server 2005 在访问数据库引擎的应用程序中引入了对多个活动结果集的支持, (MARS) 。 在 SQL Server 的早期版本中,数据库应用程序无法在单个连接上保持多个活动语句。 使用 SQL Server 默认结果集时,应用程序必须先处理或取消从某一批处理生成的所有结果集,然后才能对该连接执行任何其他批处理。 SQL Server 2005 引入了一个新的连接属性,它允许应用程序每个连接具有多个挂起请求,特别是每个连接有多个活动默认结果集。
MARS 通过以下新功能简化了应用程序设计:
应用程序可以同时打开多个默认结果集,并且交错读取它们。
应用程序可以在默认结果集打开的同时执行其他语句(例如 INSERT、UPDATE、DELETE 和存储过程调用)。
下列指南对使用 MARS 的应用程序很有帮助:
默认结果集应该用于使用单个 SQL 语句(SELECT、带 OUTPUT 的 DML、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 基础结构允许以交错方式执行多个批处理,尽管只能在定义完善的时间点切换执行。 此外,多数语句必须在同一批处理内以原子方式运行。 在将行发送到客户端时,允许将行返回到客户端的语句(有时称为 生成点)在完成前交错执行,例如:
SELECT
FETCH
RECEIVE
作为存储过程或批处理的一部分执行的任何其他语句必须运行完毕,之后才能切换到执行其他 MARS 请求。
多个批处理交错执行的确切方式受若干因素影响,很难预测包含收获点的多个批处理中的命令的确切执行顺序。 注意避免交错执行此类复杂批处理所产生的意外负面影响。
要避免这些问题,可使用 API 调用而不是 Transact-SQL 语句来管理连接状态(SET、USE)和事务(BEGIN TRAN、COMMIT、ROLLBACK),方法是不在同样包含收获点的多语句批处理中包括这些语句,以及通过使用或取消所有结果来顺序执行此类批处理。
注意
启用 MARS 时,启动手动或隐式事务的批处理或存储过程必须完成该事务,之后批处理才能退出。 如果不是这样,SQL Server 将在批处理完成时回滚该事务所做的所有更改。 这种事务由 SQL Server 作为批范围的事务管理。 这是 SQL Server 2005 中引入的一种新型事务,用于在启用 MARS 时使用现有的行为良好的存储过程。 若要详细了解批范围内的事务,请参阅事务语句 (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
。 它接受值 true
或 false
;默认值为 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 驱动程序通过添加 SQLSetConnectAttr 和 SQLGetConnectAttr 函数支持 MARS。 添加了 SQL_COPT_SS_MARS_ENABLED 以接受 SQL_MARS_ENABLED_YES 或 SQL_MARS_ENABLED_NO,默认值为 SQL_MARS_ENABLED_NO。 此外,还添加了新的连接字符串关键字 Mars_Connection
。 它接受值 "yes" 或 "no";默认值为 "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);