适用于 SQL Server 的 Microsoft OLE DB 驱动程序

下载 OLE DB 驱动程序

Microsoft OLE DB Driver for SQL Server是一个独立的数据访问应用程序接口(API),属于OLE DB的一部分。 它使 C 和 C++ 应用程序能够连接到 Azure SQL 数据库、Microsoft Fabric 中的 SQL 数据库、Azure SQL 托管实例 以及受支持版本的 SQL Server 中的 Microsoft SQL 数据库引擎。 Microsoft 于 2018 年首次发布 18 版本,并包含在 SQL Server 2019(15.x)中。

MSOLEDBSQL19 是当前驱动程序。 它通常向后兼容 SQL Server 原生客户端(SNAC),并提供了超越 SNAC 和 Windows Data Access Components(Windows DAC,前称 Microsoft Data Access Components 或 MDAC)提供的 SQL Server OLE DB 提供者的功能。

选择起点

Azure SQL的生产基线

将此代码片段用作面向生产Azure SQL连接的起点。 它从应用配置加载服务器名称和数据库名称,使用托管身份认证,确保连接字符串中不出现秘密信息,并支持表式数据流(TDS)8.0加密及完整证书验证。 它为每次连接尝试设置超时时间,并在发生瞬时故障时通过指数退避和抖动进行重试。

本文中的C++摘要省略了include、COM初始化和日志辅助工具,以便简洁。

std::wstring BuildConnectionString(const wchar_t* server, const wchar_t* database) {
    std::wstring cs = L"Provider=MSOLEDBSQL19";
    cs += L";Data Source=tcp:"; cs += server; cs += L",1433";
    cs += L";Initial Catalog="; cs += database;
    cs += L";Authentication=ActiveDirectoryMSI";   // managed identity, no stored secret
    cs += L";Use Encryption for Data=Strict";      // TDS 8.0 with certificate validation
    cs += L";Connect Timeout=30";                  // per-attempt connect timeout, in seconds
    cs += L";Connect Retry Count=3";               // idle connection resiliency, not initial connect
    cs += L";Connect Retry Interval=10";
    return cs;
}

// Transient fault codes documented for Azure SQL, plus the resource governance
// codes. Network termination and timeout errors (64, 233, 258, 10053, 10054,
// 10060) are retried a bounded number of times, which is the documented
// guidance for them. 258 is the code the driver reports for a connect timeout.
// 10053 and 10054 can also mean the encryption handshake failed rather than a
// plain network reset, so read the error text before assuming a network fault.
bool IsTransient(LONG nativeError) {
    switch (nativeError) {
        case 615: case 926: case 4060: case 4221:
        case 10928: case 10929: case 10936:
        case 40197: case 40501: case 40613:
        case 42108: case 42109:
        case 49918: case 49919: case 49920:
        case 40020: case 40143: case 40166: case 40540:   // failover subcodes
        case 64: case 233: case 258:
        case 10053: case 10054: case 10060:
            return true;
        default:
            return false;
    }
}

// Retries only errors that a new connection can clear, with exponential backoff
// plus jitter so that concurrent clients don't retry in lockstep.
HRESULT ConnectWithRetry(IDataInitialize* pDataInit, const std::wstring& connectionString,
                         int maxAttempts, IDBInitialize** ppDbInit) {
    HRESULT hr = E_FAIL;
    *ppDbInit = nullptr;
    for (int attempt = 1; attempt <= maxAttempts; ++attempt) {
        IDBInitialize* pDbInit = nullptr;
        hr = pDataInit->GetDataSource(nullptr, CLSCTX_INPROC_SERVER, connectionString.c_str(),
                                      IID_IDBInitialize, reinterpret_cast<IUnknown**>(&pDbInit));
        if (SUCCEEDED(hr) && SUCCEEDED(hr = pDbInit->Initialize())) {
            Log("INFO", "connected on attempt %d/%d", attempt, maxAttempts);
            *ppDbInit = pDbInit;
            return S_OK;
        }

        // Walks IErrorRecords and returns the first record that carries a real
        // SQL Server error number. Transport and timeout failures report a
        // generic wrapper record first, whose native error is 0. Errors the
        // server returns carry the number on the first record.
        LONG native = LogProviderErrors("connect", hr);
        if (pDbInit) pDbInit->Release();
        if (attempt == maxAttempts || !IsTransient(native)) return hr;

        // Cap the backoff at 64 seconds. This also keeps the shift in range
        // when a caller passes a large maxAttempts.
        int shift = (attempt - 1 < 6) ? attempt - 1 : 6;
        DWORD delayMs = (1UL << shift) * 1000UL + (DWORD)(GetTickCount64() % 500);
        Log("WARN", "retrying in %lu ms (attempt %d/%d)", delayMs, attempt + 1, maxAttempts);
        Sleep(delayMs);
    }
    return hr;
}

Connect Retry CountConnect Retry Interval 启用 空闲连接弹性,透明地恢复空闲时断开的连接。 它们不会重试初始连接,这也是为什么这个片段还实现了应用层的重试。 两者都留着。

此代码片段为 IDataInitialize::GetDataSource 构建其连接字符串,该字符串使用此处显示的带空格的关键字名称,例如 Use Encryption for DataConnect Retry CountIDBInitialize::Initialize 和ADO则使用不同名称表示相同设定,如 EncryptConnectRetryCount

GetDataSource 接受错误集合的名称而不产生错误,且该设置永远不会生效。 连接随后会使用驱动程序默认设置,这可能会削弱该连接。 Encrypt=Strict 在此路径上会使 MSOLEDBSQL19 上的加密保持为 Mandatory,因此该连接会放弃使用 TDS 8.0,并在明文预登录阶段协商加密,而且在 MSOLEDBSQL 上则完全关闭加密。 并非所有情况都会以开放方式失效:被错误设置的 TrustServerCertificate 也会以同样的方式被丢弃,因此该属性会保持其默认值 false,并使证书验证保持开启。

不要指望靠错误提示来发现失误。 不属于任何集合的名称,如 ZzzNotAKeyword,会产生 Invalid 连接字符串 attribute 记录,但来自错误集合的名称则不产生任何记录。 要确认某项设置已生效,请在连接之前使用 IDBProperties::GetProperties 读取该属性的值。 有关与每个 API 对应的关键字集,请参见《将连接字符串关键字与 OLE DB Driver for SQL Server 一起使用》。

OLE DB 通过错误对象而不是仅通过 HRESULT 来报告诊断信息,因此在重试之前应先对故障进行分类。 认证或配置错误会立即失败,而不是消耗全部重试预算。

有关此配置的每个部分的详细信息,请参阅:

有关 Azure SQL 瞬态错误的目录,请参见 瞬态故障错误代码

主要功能

  • Microsoft Entra ID认证:无密码连接,支持托管身份、服务主体、交互式和集成流程。
  • 严格加密:TDS 8.0连接,具备完整证书验证,19.2.0及更高版本采用TLS 1.3。
  • 空闲连接复原能力:透明地恢复在空闲状态下断开的连接。
  • 多重激活结果集(MARS):每个连接有多个待处理请求。
  • 批量复制:通过批量复制接口进行高吞吐量插入。
  • 表值参数:作为单一参数传递给服务器的完整结果集。
  • Always On 可用性组:借助 MultiSubnetFailover 提供监听器支持,以实现快速故障转移。
  • UTF-8 和 UTF-16 支持:两种编码中均支持字符数据。
  • 数据分类:分类列的敏感元数据。
  • 异步操作:非阻塞数据源和行集操作。

开始

Article Description
何时使用 OLE DB 驱动 何时选择 OLE DB Driver for SQL Server 而非其他 SQL Server 驱动程序?
下载 每个受支持的驱动程序版本的安装程序下载。
系统要求 支持的操作系统、SQL Server版本及安装前置条件。
建筑应用 头文件和库文件、安装目录结构,以及从 MDAC 升级后会发生的变化。
创建应用程序 应用程序遵循的调用顺序,从连接到执行命令再到读取结果。
支持生命周期 哪些驱动版本支持,以及每个版本何时离开支持。

配置和连接

Article Description
连接字符串关键字 驱动程序接受的每个连接字符串关键字及其可接受值。
数据源对象 创建并初始化连接所依赖的数据源和会话对象。
使用ADO配合驱动程序 通过 ADO 访问驱动程序功能,例如 MARS、查询通知和 XML 类型。
高可用性和灾难恢复 通过可用性组监听器和控制故障切换行为的关键词连接。
空闲连接弹性 自动恢复在空闲时断开的连接。
LocalDB 支持 连接 LocalDB 实例进行本地开发和测试。

认证与安全

Article Description
使用 Microsoft Entra ID 驱动程序支持的 Microsoft Entra 认证模式,包括托管身份和交互式。
加密和证书验证 设置加密和TrustServerCertificate,并控制服务器证书的验证方式。
程序化更改密码 处理过期密码并设置新密码,同时不离开你的应用。
客户端连接中的服务主体名称(SPN)支持 在连接上设置服务主体名称,使Kerberos互认证成功。
使用数据分类 阅读 SQL Server 为分类列返回的敏感性标签。

执行命令并处理结果

Article Description
命令 ICommand 接口和命令执行所基于的命令对象模型。
命令语法 驱动程序在命令文本中接受的 ODBC SQL、ISO 和 Transact-SQL 语法组合。
命令参数 在命令文本中标记参数,并为每个参数绑定驱动支持的类型。
使用多重有效结果集(MARS) 在同一连接上保持不止一个待处理结果集处于打开状态。
执行异步操作 启动某项操作而不阻塞调用线程,然后轮询或等待其完成。
处理查询通知 注册以获取查询结果在服务器上发生变化时的通知。
处理结果操作指南 执行存储过程或函数并读取返回码、输出参数和行的工作示例。

使用行集和游标

Article Description
行集 行集接口,以及决定你获得哪种行集的属性。
正在获取行 使用 IRowset 依次提取行、读取列值并释放行。
在行集中更新数据 请求 IRowsetChangeIRowsetUpdate 获得可修改的行集,并控制其锁定。
Bookmarks 保存行位置,稍后再返回到该位置,而不是按顺序重新获取。
行集与 SQL Server 光标 驱动程序何时使用默认结果集,以及何时改为打开服务器游标。

批量复制

Article Description
执行批量复制操作 通过数据文件或程序变量将大量行移入或移出表。
使用 IRowsetFastLoad 批量复制数据 通过接口IRowsetFastLoad批量复制数据到 SQL Server 表。
使用 IRowsetFastLoad 和 ISequentialStream 发送 BLOB 数据 使用 IRowsetFastLoad 将每行长度不同的 BLOB 数据流式传输到 SQL Server。

表值参数

Article Description
表值参数概述 表值参数如何在单一参数中传递多行数据给服务器。
表值参数参考 参数行集创建和参数类型发现。
将数据插入表值参数 推入模型和拉取模型用于提供表值参数行。
使用表值参数 创建一个表值参数,并将其行传递给存储过程。

处理大型和二进制数据

Article Description
BLOBs和OLE对象 通过 ISequentialStream 以流的方式读取和写入 BLOB 列。
获取大数据 将大列值分块检索,而不是一个绑定缓冲区。
设置大型数据 从消费者存储对象向服务器发送一个大列值。
FILESTREAM 支持 存储大型二进制值,可以通过SQL Server或文件系统读取。
FILESTREAM 操作指南文章 使用流式接口读取和写入 FILESTREAM 列的示例。

管理表、索引和存储过程

Article Description
表格与索引 通过 IIndexDefinitionITableDefinition 创建、修改和删除表和索引。
创建 SQL Server 表 定义列并调用 ITableDefinition::CreateTable 创建表。
创建 SQL Server 索引 使用 IIndexDefinition::CreateIndex 在现有表上定义新索引。
存储过程 调用一个带有ODBC CALL语法或RPC的存储过程,读取其返回码和输出参数。

数据类型

Article Description
数据类型概述 当你绑定参数和列时,SQL Server类型如何映射到OLE DB类型。
行集和参数中的数据类型映射 行集列和命令参数的完整类型映射表。
使用大值类型 绑定 varchar(max)、nvarchar(max)和 varbinary(max) 类型。
使用 XML 数据类型 将XML文档和片段存储和检索到XML列中。
使用用户自定义类型 绑定 CLR 用户定义类型,驱动程序将其表示为带有类型元数据的二进制值。
稀疏柱支撑 驱动程序对稀疏列的支持,这些稀疏列经过优化以存储 NULL 值。
UTF-8 支持 使用 UTF-8 服务器排序规则和 UTF-8 客户端编码。
UTF-16支持 驱动程序在填充客户端缓冲区时如何处理代理配对。
日期和时间改进 绑定 date、time、datetime2 和 datetimeoffset 类型,以及这些类型所允许的转换。

Transactions

Article Description
交易概述 本地事务支持,以及用于分布式事务的 Microsoft 分布式事务处理协调器。
隔离级别 设置会话的隔离级别,以及每个级别允许的并发。
使用快照隔离 使用行版本控制可提高读取并发性,而不阻塞写入操作。
支持分布式事务 使用 ITransactionJoin::JoinTransaction 使会话加入分布式事务。

诊断和故障排除

Article Description
错误 驱动程序如何报告故障,以及哪些接口包含详细信息。
获取错误信息 遍历错误接口以读取消息文本、SQLSTATE 和本机错误编号。
访问扩展事件日志中的诊断信息 打开驾驶员追踪,阅读由此产生的扩展事件日志。
已知问题 当前驱动中的未解决问题,以及可用的变通方法(如有)。
发行说明 每个驱动版本中发生了哪些变化,先从最新的开始。

迁移到当前版本的驱动程序

用于 SQL Server 的 Microsoft OLE DB 提供程序共有三代。 对于新的和现有的应用程序,请使用 MSOLEDBSQL19,并将现有的连接字符串转换为它。 OLE DB提供商于2018年 取消升级 并重新发布。

Generation 提供者字符串 地位
Microsoft OLE DB Driver for SQL Server(本文) MSOLEDBSQL19MSOLEDBSQL 支持. MSOLEDBSQL19 是当前使用的驱动程序,也是新开发时应使用的驱动程序。
SQL Server 原生客户端(SNAC) SQLNCLI11SQLNCLI 已从 SQL Server 2022 和 SQL Server Management Studio 19 中移除。 不建议用于新的开发。
Microsoft OLE DB Provider for SQL Server SQLOLEDB 包含在Windows Data Access Components中。 不再维护。 不建议用于新的开发。
Article Description
MSOLEDBSQL 主版本差异 OLE DB Driver 19 与版本 18 之间的重大变更,包括加密默认值、属性类型变更和迁移步骤。
从MDAC更新应用 旧的 OLE DB Provider for SQL Server 和当前驱动之间发生了哪些变化?更新前需要检查哪些内容?
从 SQL Server 2005 Native Client 更新应用程序 自 SQL Server 2005 (9.x) 中的 SQL Server Native Client 以来,适用于 SQL Server 的 OLE DB 驱动程序中的破坏性变更。

Reference

Article Description
适用于 SQL Server 的 OLE DB 驱动程序功能 驱动程序特定功能索引及其各自的文档位置。
OLE DB 编程 驱动所展示的 COM API 模型,以及它如何通过 TDS 与 SQL Server 通信。
OLE DB 操作指南文章 OLE DB操作指南索引,按任务分组。
OLE 数据库接口 该驱动程序中表现出提供者特定行为的 OLE DB 接口和方法。
模式行集支持 提供者特定的模式行集行为,包括从链接服务器返回的元数据。
查找更多信息 本文档集之外的规范、示例和社区资源。