ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

MySQL ODBC 环境搭建与 C++ 连接实战:从驱动安装到查询 Demo

MySQL ODBC 环境搭建与 C++ 连接实战:从驱动安装到查询 Demo

简介:这是一份面向C++开发者与数据库初学者的MySQL ODBC连接实践项目,重点演示如何通过ODBC API在C++程序中完成与MySQL数据库的通信。内容涵盖ODBC数据源配置、环境与连接句柄初始化、SQL语句执行、结果集遍历以及连接释放等完整流程,并配有对话框界面、自定义列表控件和记录增删改等模块,便于理解数据库操作在MFC工程中的落地方式。压缩包共26个文件,约38KB,以h头文件与cpp源文件为主,另含dsp、dsw工程文件、rc资源脚本及aps、clw等Visual Studio辅助文件,可直接在旧版VS环境中打开编译。目前已有1024人学习下载,适合希望掌握ODBC连接机制、对照代码排查连接与查询问题的读者参考。

1. 从一次编译报错说起:MySQL ODBC 在 C++ 里到底怎么装

上周帮一个做数据同步工具的朋友排查问题,他的 C++ 程序在本地跑得好好的,一放到测试机上就报Data source name not found and no default driver specified。折腾了一下午,最后发现是测试机上只装了 MySQL Connector/ODBC 的 32 位版本,而他的程序编译成了 64 位。这种坑在 MySQL ODBC 环境搭建里太常见了——驱动位数、DSN 配置、字符集编码,任何一个环节对不上,程序就是连不上数据库。

MySQL ODBC 这套东西,说白了就是让 C++ 程序通过 ODBC 接口去连 MySQL。它不像直接链 MySQL C API 那样需要编译时链接库文件,而是把连接信息交给驱动管理器去处理。好处是换数据库时改 DSN 就行,不用重新编译;坏处是环境依赖多了一层,装不好就各种玄学报错。这篇笔记面向的是需要在 Windows 或 Linux 上用 C++ 通过 ODBC 连 MySQL 的开发者,从驱动安装、DSN 配置到代码验证,一步步走完,最后能跑通一个查询 Demo。

2. 环境准备:MySQL ODBC 驱动版本选择与安装

2.1 先确认 MySQL 服务端版本和位数

装驱动之前,第一件事是确认你连的 MySQL 服务端是什么版本。MySQL 8.0 和 5.7 在认证插件上有差异,8.0 默认用caching_sha2_password,老版本的 ODBC 驱动可能不认。我一般会先在数据库那台机器上执行:

mysql --version # 输出示例:mysql Ver 8.0.36 for Linux on x86_64 (MySQL Community Server - GPL)

如果服务端是 8.0,ODBC 驱动最好选 8.0.x 系列,避免认证插件不兼容。另外要确认服务端和客户端程序的位数是否一致——64 位程序必须配 64 位驱动,32 位程序配 32 位驱动,混用就是开头那个报错。

2.2 Windows 下安装 MySQL Connector/ODBC

Windows 上直接去 MySQL 官方下载 MSI 安装包。我一般选mysql-connector-odbc-8.0.36-winx64.msi这种带winx64后缀的,安装时注意勾选 Custom 安装,把驱动装到你想要的路径。

安装完成后,在「ODBC 数据源管理器」里能看到驱动列表。64 位系统的入口是C:\Windows\System32\odbcad32.exe,32 位的入口是C:\Windows\SysWOW64\odbcad32.exe。这两个别搞混,很多人打开的是 32 位管理器,配完 DSN 发现 64 位程序读不到,就是这个问题。

# 验证驱动是否注册成功(PowerShell) Get-OdbcDriver | Where-Object { $_.Name -like "*MySQL*" } # 正常输出会列出 MySQL ODBC 8.0 Unicode Driver 和 ANSI Driver

2.3 Linux 下安装 unixODBC 和 MySQL ODBC 驱动

Linux 上分两步:先装 ODBC 驱动管理器 unixODBC,再装 MySQL 的 ODBC 驱动。以 Ubuntu 22.04 为例:

# 安装 unixODBC 和 MySQL ODBC 驱动 sudo apt update sudo apt install -y unixodbc unixodbc-dev sudo apt install -y mysql-connector-odbc # 验证驱动是否注册 odbcinst -q -d # 输出应包含 [MySQL ODBC 8.0 Unicode Driver]

如果 apt 源里的驱动版本太老,可以去 MySQL 官网下.deb或.tar.gz包手动装。手动装的话,装完要检查/etc/odbcinst.ini里有没有对应的驱动条目,没有就手动加:

# /etc/odbcinst.ini 片段 [MySQL ODBC 8.0 Unicode Driver] Description = MySQL ODBC 8.0 Unicode Driver Driver = /usr/lib/x86_64-linux-gnu/odbc/libmyodbc8w.so UsageCount = 1

Driver路径要指向实际.so文件的位置,可以用find / -name "libmyodbc*"找一下。路径写错的话,后面isql测试会直接报驱动加载失败。

3. 配置 DSN:ODBC 数据源怎么填才不出错

3.1 DSN 的两种类型:用户 DSN 和系统 DSN

ODBC 数据源分用户 DSN 和系统 DSN。用户 DSN 只对当前登录用户可见,系统 DSN 对所有用户可见。我一般推荐用系统 DSN,尤其是程序以服务方式运行时,用户 DSN 经常读不到。

Windows 上在 ODBC 管理器里点「系统 DSN」→「添加」→ 选 MySQL ODBC 8.0 Unicode Driver,然后填这些关键项:

配置项填写内容说明
Data Source NameMySQLTest程序里用的 DSN 名
TCP/IP Server127.0.0.1数据库地址
Port3306默认端口
Userroot数据库用户名
Password你的密码数据库密码
Databasetestdb要连的库名
Character Setutf8mb4字符集,建议和库一致

填完点 Test,显示 Connection Successful 才算配好。如果报Can't connect to MySQL server,先检查网络和端口;报Access denied就是用户名密码或权限问题。

3.2 Linux 下用 odbc.ini 配置 DSN

Linux 没有图形界面,DSN 写在/etc/odbc.ini或~/.odbc.ini里。系统级配置放/etc/odbc.ini:

# /etc/odbc.ini [MySQLTest] Description = MySQL Test DSN Driver = MySQL ODBC 8.0 Unicode Driver Server = 127.0.0.1 Port = 3306 User = root Password = your_password Database = testdb Charset = utf8mb4

Driver这一项必须和/etc/odbcinst.ini里的节名完全一致,大小写敏感。配完后用isql测试:

# 测试 DSN 连通性 isql -v MySQLTest root your_password # 成功会进入 SQL> 提示符,执行 select version(); 能返回结果

如果isql报[IM002][unixODBC][Driver Manager]Data source name not found,说明 DSN 名没匹配上,检查odbc.ini里的节名和命令里写的是否一致。

3.3 连接字符串方式:不配 DSN 也能连

有些场景不方便配 DSN,比如容器里临时跑个程序。这时候可以用连接字符串直接连,C++ 代码里把 DSN 换成完整的连接串:

// 不依赖 DSN 的连接字符串示例 std::string connStr = "DRIVER={MySQL ODBC 8.0 Unicode Driver};" "SERVER=127.0.0.1;" "PORT=3306;" "DATABASE=testdb;" "USER=root;" "PASSWORD=your_password;" "CHARSET=utf8mb4;";

这种方式的好处是部署时不用改系统配置,坏处是密码明文写在代码或配置文件里,要注意权限管理。我一般会在生产环境用 DSN,开发和测试环境用连接字符串,灵活一些。

4. C++ 代码实战:从连接 MySQL 到查询数据

4.1 引入头文件和链接 ODBC 库

Windows 上 ODBC 的头文件是<windows.h>和<sql.h>、<sqlext.h>,链接odbc32.lib。Linux 上头文件在/usr/include/sql.h等,链接-lodbc。

// main.cpp #include <iostream> #include <string> #include <windows.h> // Windows 需要 #include <sql.h> #include <sqlext.h> // Linux 下不需要 windows.h,直接包含 sql.h 和 sqlext.h

编译命令:

# Linux 编译 g++ -o mysql_odbc_demo main.cpp -lodbc # Windows (MSVC) cl main.cpp odbc32.lib

如果编译时报sql.h: No such file or directory,说明 unixodbc-dev 没装,回头执行sudo apt install unixodbc-dev。

4.2 连接数据库并执行查询

下面是一个完整的查询示例,连上 DSN 后查user表的前几行:

#include <iostream> #include <sql.h> #include <sqlext.h> int main() { SQLHENV env; SQLHDBC dbc; SQLHSTMT stmt; SQLRETURN ret; // 1. 分配环境句柄 SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env); SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0); // 2. 分配连接句柄并连接 SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc); ret = SQLConnect(dbc, (SQLCHAR*)"MySQLTest", SQL_NTS, // DSN 名 (SQLCHAR*)"root", SQL_NTS, // 用户名 (SQLCHAR*)"your_password", SQL_NTS); // 密码 if (!SQL_SUCCEEDED(ret)) { std::cerr << "连接失败" << std::endl; return 1; } // 3. 分配语句句柄并执行查询 SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt); SQLExecDirect(stmt, (SQLCHAR*)"SELECT id, name FROM user LIMIT 5", SQL_NTS); // 4. 绑定结果列并取数据 int id; char name[64]; SQLLEN idLen, nameLen; SQLBindCol(stmt, 1, SQL_C_LONG, &id, 0, &idLen); SQLBindCol(stmt, 2, SQL_C_CHAR, name, sizeof(name), &nameLen); while (SQLFetch(stmt) == SQL_SUCCESS) { std::cout << "id=" << id << " name=" << name << std::endl; } // 5. 释放句柄 SQLFreeHandle(SQL_HANDLE_STMT, stmt); SQLDisconnect(dbc); SQLFreeHandle(SQL_HANDLE_DBC, dbc); SQLFreeHandle(SQL_HANDLE_ENV, env); return 0; }

SQLConnect的第三个参数是 DSN 名,要和odbc.ini或 Windows 系统 DSN 里配的完全一致。SQLBindCol把结果集的列绑定到 C++ 变量上,SQLFetch逐行读取。字符集方面,如果数据库是 utf8mb4,用SQL_C_CHAR取中文一般没问题,但 Windows 控制台默认 GBK,输出中文可能乱码,需要SetConsoleOutputCP(65001)切到 UTF-8。

4.3 错误处理:拿到具体的报错信息

ODBC 的报错信息不会直接告诉你哪里错了,需要用SQLGetDiagRec去取。我一般封装一个函数:

void printOdbcError(SQLSMALLINT handleType, SQLHANDLE handle) { SQLCHAR sqlState[6], message[256]; SQLINTEGER nativeError; SQLSMALLINT msgLen; SQLSMALLINT i = 1; while (SQLGetDiagRec(handleType, handle, i, sqlState, &nativeError, message, sizeof(message), &msgLen) != SQL_NO_DATA) { std::cerr << "SQLState: " << sqlState << " NativeError: " << nativeError << " Message: " << message << std::endl; i++; } }

连接失败时调用printOdbcError(SQL_HANDLE_DBC, dbc),就能看到类似SQLState: 28000这种具体错误码,比只打印「连接失败」有用得多。

5. 避坑与排查:MySQL ODBC 安装配置常见问题

5.1 驱动位数不匹配导致 DSN 找不到

现象:程序报Data source name not found and no default driver specified,但 ODBC 管理器里明明能看到 DSN。

原因:程序是 64 位,DSN 配在 32 位管理器里,或者反过来。

解决:确认程序位数,用对应位数的 ODBC 管理器重新配 DSN。Windows 上 64 位管理器是System32\odbcad32.exe,32 位是SysWOW64\odbcad32.exe。Linux 上用odbcinst -j看驱动管理器的位数。

5.2 MySQL 8.0 认证插件不兼容

现象:连接时报Authentication plugin 'caching_sha2_password' cannot be loaded。

原因:老版本 ODBC 驱动不支持 MySQL 8.0 默认的caching_sha2_password认证插件。

解决:升级 ODBC 驱动到 8.0.x 版本,或者把用户认证插件改成mysql_native_password:

ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'your_password'; FLUSH PRIVILEGES;

改完记得重启 MySQL 服务。

5.3 字符集配置不对导致中文乱码

现象:查询出来的中文显示为???或乱码。

原因:DSN 里没配Charset,或者配成了latin1。

解决:在 DSN 配置里把Charset设为utf8mb4,和数据库的字符集保持一致。Windows 控制台输出时还要注意代码页,用chcp 65001切到 UTF-8。

5.4 Linux 下驱动路径写错

现象:isql测试时报Can't open lib '/usr/lib/.../libmyodbc8w.so': file not found。

原因:odbcinst.ini里的Driver路径不对,或者.so文件没装。

解决:用find / -name "libmyodbc*"找到实际路径,更新odbcinst.ini。如果找不到文件,说明驱动没装成功,重新安装mysql-connector-odbc。

5.5 连接超时或端口不通

现象:连接时卡很久然后报Can't connect to MySQL server on '127.0.0.1'。

原因:MySQL 没启动、端口不对、防火墙拦截,或者bind-address只监听了 localhost。

解决:先telnet 127.0.0.1 3306测端口通不通,不通就检查 MySQL 服务状态和防火墙规则。如果 MySQL 配了bind-address = 127.0.0.1,远程连接需要改成0.0.0.0并重启服务。

6. 装完怎么验证:一个最小可跑通的检查清单

装完驱动、配完 DSN、写完代码,别急着往生产环境扔。我一般会按这个顺序走一遍验证,每一步都过了再往下走。

第一步,确认驱动注册成功。Windows 上执行Get-OdbcDriver | Where-Object { $_.Name -like "*MySQL*" },Linux 上执行odbcinst -q -d,能看到 MySQL ODBC 驱动条目才算过。

第二步,用isql或 ODBC 管理器测试 DSN 连通性。isql -v MySQLTest root your_password能进到SQL>提示符,执行select version();能返回版本号,说明 DSN 配置没问题。

第三步,编译并运行 C++ Demo。把第 4 章的代码存成main.cpp,编译后运行,能看到查询结果输出。如果连接失败,用printOdbcError打印具体错误码,对照第 5 章的排查表定位。

第四步,验证中文和特殊字符。在数据库里插一条带中文的记录,用 Demo 查出来看是否乱码。这一步很多人会跳过,等到上线才发现问题。

第五步,验证程序位数和驱动位数一致。用file命令(Linux)或dumpbin /headers(Windows)确认程序位数,再确认 DSN 配在对应位数的管理器里。

# Linux 下确认程序位数 file mysql_odbc_demo # 输出示例:ELF 64-bit LSB executable, x86-64 # 确认 ODBC 管理器位数 odbcinst -j # 输出中的 DRIVERS 路径包含 lib64 就是 64 位

这套流程走下来,基本能覆盖 90% 的安装配置问题。从那以后我每次在新机器上配 MySQL ODBC,都强制走一遍这个清单,不再凭感觉「应该没问题」。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进