C语言如何高效访问Access数据库?

99ANYc3cd6
预计阅读时长 29 分钟
位置: 首页 C语言 正文

核心概念

  1. ADO (ActiveX Data Objects):这是我们要使用的库,它提供了一组对象(如 Connection, Command, Recordset)来管理数据库连接、执行命令和处理数据。
  2. ODBC (Open Database Connectivity):ADO 底层通常通过 ODBC 驱动程序与数据库通信,你需要确保你的系统上安装了 Access 数据库的 ODBC 驱动程序(通常包含在 Office 或 Windows 的数据访问组件中)。
  3. 连接字符串 (Connection String):这是一个包含连接数据库所需所有信息的字符串,例如数据库文件路径、提供者、用户名和密码等。
  4. #import 指令:这是 C++ 的一个预处理指令,它能够读取一个 COM 类型库(如 msado15.dll)并自动为你生成 C++ 的头文件和封装类,极大地简化了 COM 对象的使用,这是在 C++ 中使用 ADO 的标准方式。

第一步:环境准备

  1. 安装 Access 数据库引擎

    c语言 access数据库
    (图片来源网络,侵删)
    • 你的开发机器上需要安装 Access 数据库引擎,这样才能有 ODBC 驱动和 ADO 的底层支持。
    • 下载并安装 Microsoft Access Database Engine 2025 Redistributable(或与你 Access 文件版本匹配的版本,如 2007, 2010 等),即使你没有安装 Office,也需要这个。
    • 下载地址:https://www.microsoft.com/en-us/download/details.aspx?id=54920
  2. 创建一个示例 Access 数据库

    • 创建一个名为 mydatabase.accdb 的 Access 文件。
    • 在其中创建一个表,Students
    • Students 表结构如下: | 字段名 | 数据类型 | 说明 | | :--- | :--- | :--- | | ID | 自动编号 | 主键 | | Name | 文本 | 学生姓名 | | Age | 数字 | 年龄 |
    • 插入几条示例数据。

第二步:C++ 项目配置 (以 Visual Studio 为例)

  1. 创建项目:打开 Visual Studio,创建一个新的 C++ 空项目Windows 控制台应用

  2. 设置项目字符集

    • 为了避免中文字符乱码,建议将项目设置为使用 多字节字符集
    • 右键点击项目 -> 属性 -> 配置属性 -> 高级 -> 将 字符集 从 "使用 Unicode 字符集" 改为 "使用多字节字符集"
  3. 包含 ADO 库

    c语言 access数据库
    (图片来源网络,侵删)
    • 在你的 C++ 源文件(main.cpp)的开头,添加 #import 指令,这会引入 ADO 库。
      // 引入 ADO 类型库,路径通常是系统目录
      #import "C:\\Program Files\\Common Files\\System\\ado\\msado15.dll" no_namespace rename("EOF", "adoEOF")
    • no_namespace:告诉编译器不要使用 ADODB 命名空间,直接使用全局对象,简化代码。
    • rename("EOF", "adoEOF"):将 ADO 中的 EOF (End Of File) 标志重命名为 adoEOF,因为它与 C/C++ 标准库中的 EOF 宏冲突。
  4. 链接库

    • ADO 是基于 COM 的,需要链接 ole32.liboleaut32.lib
    • 右键点击项目 -> 属性 -> 配置属性 -> 链接器 -> 输入 -> 在 附加依赖项 中添加 ole32.liboleaut32.lib

第三步:编写 C++ 代码

下面是一个完整的示例代码,演示了如何连接到 Access 数据库,查询数据,并插入新数据。

#include <iostream>
#include <windows.h> // 用于 CoInitialize 和 CoUninitialize
// 引入 ADO 类型库
// 注意:如果找不到路径,可以使用 "msado15.dll",编译器会在系统目录中查找
#import "C:\\Program Files\\Common Files\\System\\ado\\msado15.dll" no_namespace rename("EOF", "adoEOF")
// 为了使用 cout 和 endl
using namespace std;
int main()
{
    // 1. 初始化 COM 库
    // 这是使用 ADO 等 COM 组件的必要步骤
    HRESULT hr = CoInitialize(NULL);
    if (FAILED(hr))
    {
        cout << "Failed to initialize COM library. Error code: 0x" << hex << hr << endl;
        return 1;
    }
    // 使用 _com_ptr_ptr 智能指针来管理 ADO 对象的生命周期
    // 它会在作用域结束时自动释放资源,避免内存泄漏
    _ConnectionPtr pConn(__uuidof(Connection));
    _RecordsetPtr pRst(__uuidof(Recordset));
    _CommandPtr pCmd(__uuidof(Command));
    try
    {
        // 2. 定义连接字符串
        // Provider=Microsoft.ACE.OLEDB.12.0; 是用于 .accdb 文件的提供者
        // Data Source= 指定你的 .accdb 文件路径
        // Jet OLEDB:Database Password= 你的密码(如果有)
        _bstr_t strConnectStr(L"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\\path\\to\\your\\mydatabase.accdb;");
        // 3. 打开连接
        cout << "Connecting to database..." << endl;
        pConn->Open(strConnectStr, L"", L"", adConnectUnspecified);
        cout << "Connection successful!" << endl;
        // --- 示例 1:查询数据 ---
        cout << "\n--- Querying Data: ---" << endl;
        // 执行 SQL 查询
        pRst = pConn->Execute(L"SELECT ID, Name, Age FROM Students", NULL, adCmdText);
        // 遍历记录集
        if (!pRst->adoEOF)
        {
            cout << "ID\tName\tAge" << endl;
            cout << "-------------------" << endl;
            while (!pRst->adoEOF)
            {
                // 使用 _variant_t 来处理数据库中的各种数据类型
                _variant_t varID = pRst->GetCollect(L"ID");
                _variant_t varName = pRst->GetCollect(L"Name");
                _variant_t varAge = pRst->GetCollect(L"Age");
                // 安全地提取数据
                cout << (varID.vt != VT_NULL ? varID.lVal : 0) << "\t";
                cout << (varName.vt != VT_NULL ? (char*)varName.bstrVal : "NULL") << "\t";
                cout << (varAge.vt != VT_NULL ? varAge.lVal : 0) << endl;
                // 移动到下一条记录
                pRst->MoveNext();
            }
        }
        else
        {
            cout << "No records found." << endl;
        }
        // 关闭记录集
        if (pRst->State == adStateOpen)
        {
            pRst->Close();
        }
        // --- 示例 2:插入数据 ---
        cout << "\n--- Inserting Data: ---" << endl;
        // 使用 Command 对象执行参数化查询,防止 SQL 注入
        pCmd->ActiveConnection = pConn;
        pCmd->CommandText = L"INSERT INTO Students (Name, Age) VALUES (?, ?)";
        pCmd->Parameters->Append(pCmd->CreateParameter(L"@pName", adVarWChar, adParamInput, 50, L"张三"));
        pCmd->Parameters->Append(pCmd->CreateParameter(L"@pAge", adInteger, adParamInput, 4, (long)25));
        pCmd->Execute(NULL, NULL, adCmdText);
        cout << "A new record '张三, 25' has been inserted." << endl;
        // 清空参数,以便下次使用
        pCmd->Parameters->Refresh();
        // 重新查询以验证插入
        cout << "\n--- Verifying Insertion: ---" << endl;
        pRst = pConn->Execute(L"SELECT * FROM Students WHERE Name='张三'", NULL, adCmdText);
        if (!pRst->adoEOF)
        {
            cout << "New record found: ";
            cout << (char*)pRst->GetCollect(L"Name")->bstrVal << ", ";
            cout << pRst->GetCollect(L"Age")->lVal << endl;
        }
        pRst->Close();
    }
    catch (_com_error& e)
    {
        // 捕获并显示 ADO 错误
        cout << "ADO Error: " << e.ErrorMessage() << endl;
        cout << "Error Description: " << e.Description() << endl;
    }
    catch (...)
    {
        // 捕获其他未知错误
        cout << "An unknown error occurred." << endl;
    }
    // 4. 清理资源
    if (pConn->State == adStateOpen)
    {
        pConn->Close();
    }
    // 释放 COM 资源
    CoUninitialize();
    cout << "\nPress any key to exit...";
    cin.get();
    return 0;
}

第四步:编译和运行

  1. 替换路径:将代码中的 C:\\path\\to\\your\\mydatabase.accdb 替换为你实际的 Access 数据库文件路径。
  2. 生成解决方案:在 Visual Studio 中按 F7 或点击 "生成" -> "生成解决方案"。
  3. 运行:按 Ctrl + F5 运行程序,这会运行程序并在结束后暂停,让你能看到输出结果。

你应该能看到程序成功连接数据库,打印出 Students 表中的数据,然后插入一条新记录并再次查询显示出来。


常见问题与注意事项

  1. _com_error 异常:ADO 操作会抛出 _com_error 异常,务必使用 try...catch 块来捕获,否则程序可能崩溃。
  2. 数据类型 (_variant_t):ADO 返回的数据是 _variant_t 类型,它是一个可以容纳多种数据类型的联合体,你需要检查其 vt (value type) 成员来确定数据的具体类型,然后安全地提取值。
    • VT_BSTR: 字符串,用 .bstrVal 获取。
    • VT_I4VT_INT: 32位整数,用 .lVal 获取。
    • VT_R8: 8位浮点数,用 .dblVal 获取。
    • VT_NULL: 表示数据库中的 NULL 值。
  3. 连接字符串
    • .accdb 文件 (Access 2007 及以后): Provider=Microsoft.ACE.OLEDB.12.0;
    • .mdb 文件 (Access 2003 及以前): Provider=Microsoft.Jet.OLEDB.4.0;
    • 如果数据库有密码,在连接字符串中添加 Jet OLEDB:Database Password=YourPassword;
  4. SQL 注入:永远不要将用户输入直接拼接到 SQL 语句中,像示例中那样使用 参数化查询 是最安全的做法。
  5. 字符集问题:如果你的项目使用 Unicode,连接字符串和 SQL 语句需要使用 L"..." 宽字符形式,_variant_t 处理字符串时也要小心,使用多字节字符集通常更简单,尤其是在处理中文时。
  6. 找不到 msado15.dll#import 路径报错,可以只写文件名 #import "msado15.dll",前提是该 DLL 在系统的 PATH 环境变量中(通常在 System32 目录下)。

替代方案

虽然 ADO 是最标准的方法,但在某些情况下,你也可以考虑:

c语言 access数据库
(图片来源网络,侵删)
  • C API (ODBC API):这是更底层的 C 语言接口,它不依赖 C++,但代码会更繁琐,需要手动管理句柄、分配和释放内存,非常容易出错,不推荐初学者使用。
  • 第三方库:如 OTL (Oracle, Odbc, and DB2-CLI Template Library),它是一个功能强大的 C++ 模板库,可以简化数据库操作,支持多种数据库,包括 ODBC,它提供了比原生 ADO 更现代的 C++ 风格。

对于在 C++ (兼容 C) 中访问 Access 数据库,使用 #import 引入 ADO 库 是最推荐、功能最全且相对容易上手的方法,希望这份详细的指南能帮助你成功实现!

-- 展开阅读全文 --
头像
dede上传图片如何保持原文件名不变?
« 上一篇 03-15
scanf返回值究竟该怎么用?
下一篇 » 03-15

相关文章

取消
微信二维码
支付宝二维码

目录[+]