一、使用准備
環境:CentOS 7.6和Ubuntu 16.04,MySQL 5.7
C++ MySQL連接相關庫下載
下載地址:MySQL Community Downloads
有兩種選擇,C API和Connector/C++,貌似C API簡單一點,Connector/C++比較規范,和Java JDBC接口一致。這里選擇C API
翻譯一下:
C API(libmysqlclient)是用於C開發的客戶端庫:
對於C語言和SQL:
- 適用於MySQL 8.0、5.7、5.6、5.5
- 我們建議使用MySQL 8.0 C API
C API(libmysqlclient)包含在MySQL 8.0中(其他版本也可以在其安裝文件夾中找到,通過某些特殊手段安裝的可能就沒有)
Linux:可從MySQL Community Server下載頁面獲得Client Utilities Package
Repos: 可以從 Yum, APT, SuSE 倉庫獲得Client Utilities Package
Windows:可從Windows Installer獲得Client Utilities Package
以前的GA版本可從MySQL Product Archives中獲得
在線文檔地址:MySQL C API
翻到C API在線文檔查看其使用說明:
該文檔說明了如何在Linux上編譯MySQL客戶端。請仔細閱讀,比如使用gcc編譯器,注意:以下部分均復制自官方文檔,為求准確,建議瀏覽官方文檔原文
1、引用頭文件:
編譯使用MySQL頭文件的客戶端程序時,可能需要指定-I選項,以便編譯器可以找到它們。例如,如果頭文件安裝在 /usr /local/mysql/include 中,請在compile命令中使用以下選項:
-I/usr/local/mysql/include
2、鏈接庫文件
您可以將代碼與動態或靜態MySQL C客戶端庫鏈接。動態庫的基本名稱為libmysqlclient,后綴因平台而異(例如,對於Linux為.so,對於macOS為.dylib)。在所有平台上,靜態庫均名為libmysqlclient.a。
必須使用link命令中的-lmysqlclient選項鏈接MySQL客戶端。您可能還需要指定-L選項,以告知鏈接器在哪里可以找到該庫。例如,如果該庫安裝在/usr/local/mysql/lib中,請在鏈接命令中使用以下選項:
-L/usr/local/mysql/lib -lmysqlclient
路徑名稱在您的系統上可能有所不同。根據需要調整-I和-L選項。
為了使在Unix上編譯MySQL程序更簡單,請使用mysql_config腳本。請參見Section 4.7.1, “mysql_config — Display Options for Compiling。
mysql_config顯示編譯或鏈接所需的選項:
mysql_config --cflags
mysql_config --libs
您可以在命令行中使用反引號使用 mysql_config ,以包含它為特定選項生成的輸出。例如,要編譯和鏈接MySQL客戶端程序,請使用 mysql_config ,如下所示:
gcc -c `mysql_config --cflags` progname.c gcc -o progname progname.o `mysql_config --libs`
詳情請閱讀mysql-config使用文檔
在Unix上,默認情況下鏈接使用動態庫。要鏈接到靜態客戶端庫,請將其路徑名添加到link命令。例如,如果該庫位於/usr/local/mysql/lib中,則像這樣鏈接:
gcc -o progname progname.o /usr/local/mysql/lib/libmysqlclient.a
或使用mysql_config提供庫的路徑:
gcc -o progname progname.o `mysql_config --variable=pkglibdir`/libmysqlclient.a
mysql_config 當前不提供列出靜態鏈接所需的所有庫的方法,因此可能有必要在鏈接命令上命名其他庫(例如,在Solaris上為-lnsl -lsocket)。要了解要添加哪些庫,請使用 mysql_config --libs 和 ldd libmysqlclient.so(或macOS上的 otool -L libmysqlclient.dylib)。
pkg-config可以代替mysql_config來獲取信息,例如編譯MySQL應用程序所需的編譯器標志或鏈接庫。例如,以下幾對命令是等效的:
mysql_config --cflags pkg-config --cflags mysqlclient mysql_config --libs pkg-config --libs mysqlclient
關於 pkg-config 使用請自行百度,文檔比較多。
3、解決鏈接到MySQL客戶端庫的問題
MySQL客戶端庫包括內置的SSL支持。在鏈接時無需指定-lssl或-lcrypto。這樣做實際上可能導致運行時出現問題。
如果鏈接器找不到MySQL客戶端庫,則對於以mysql_開頭的符號,您可能會收到未定義的引用錯誤,例如以下所示:
/tmp/ccFKsdPa.o: In function `main': /tmp/ccFKsdPa.o(.text+0xb): undefined reference to `mysql_init' /tmp/ccFKsdPa.o(.text+0x31): undefined reference to `mysql_real_connect' /tmp/ccFKsdPa.o(.text+0x69): undefined reference to `mysql_error' /tmp/ccFKsdPa.o(.text+0x9a): undefined reference to `mysql_close'
您應該能夠通過在鏈接命令的末尾添加 -Ldir_path -lmysqlclient 來解決此問題,其中 dir_path 表示客戶端庫所在目錄的路徑名。要確定正確的目錄,請嘗試以下命令:
mysql_config --libs
mysql_config 的輸出可能指示在鏈接命令上也應指定其他庫。您可以使用反引號將mysql_config輸出直接包含在編譯或鏈接命令中。例如:
gcc -o progname progname.o `mysql_config --libs`
如果在鏈接時發生錯誤,即未定義下限符號,請通過在編譯/鏈接行的末尾添加-lm來鏈接至數學庫。同樣,如果對於系統上應該存在的其他功能(例如connect())出現未定義的引用錯誤,請查看手冊頁中所涉及的功能,以確定應將哪些庫添加到鏈接命令中。
如果對於系統中不存在的函數,出現諸如以下的未定義引用錯誤,則通常意味着您的MySQL客戶端庫是在與您的系統不100%兼容的系統上編譯的:
mf_format.o(.text+0x201): undefined reference to `__lxstat'
在這種情況下,您應該下載最新版本的MySQL的源發行版,然后自己編譯MySQL客戶端庫。請參見Section 2.9, “Installing MySQL from Source”.
二、使用demo
在Ubuntu16.04上:
MySQL是直接使用apt-get安裝的,默認版本為5.7.30,測試一下mysql_config:
qb@qb-desktop:/usr$ mysql_config --cflags -I/usr/include/mysql qb@qb-desktop:/usr$ mysql_config --libs -L/usr/lib/x86_64-linux-gnu -lmysqlclient -lpthread -lz -lm -lrt -lssl -lcrypto -ldl qb@qb-desktop:/usr$ which mysql_config /usr/bin/mysql_config qb@qb-desktop:/usr$ mysql_config --version 5.7.30 qb@qb-desktop:/usr$
注意:如果mysql_config不存在,按提示安裝即可。
在CentOS 7上:
mysql_config不存在,yum也無法安裝,這上面的MySQL是通過第三方rpm源安裝的。搜索一下:發現沒有頭文件
[root@jxh ~]# find / -name mysql_config [root@jxh ~]# whereis mysql mysql: /usr/bin/mysql /usr/lib64/mysql /usr/share/mysql /usr/share/man/man1/mysql.1.gz [root@jxh ~]# cd /usr/lib64/mysql/ [root@jxh mysql]# ls libmysqlclient_r.so.18 libmysqlclient.so.18 libmysqlclient.so.20 mecab libmysqlclient_r.so.18.1.0 libmysqlclient.so.18.1.0 libmysqlclient.so.20.3.16 plugin
發現只有動態庫,按照 Centos下查看mysql的版本 查看版本為 5.7.29
所以把Ubuntu上的頭文件和庫文件拷貝過來使用(我的開發環境搭載CentOS 7上)應該是可以的。
在Ubuntu上 /usr/lib/x86_64-linux-gnu查看mysq庫文件
和CentOS 7上 5.7.29版本的基本一致,這里選擇把 libmysqlclient.a靜態庫和/usr/include/mysql下的頭文件都拷過去。
然后參照以下文章進行調用,測試通過
[1] VS2017項目中使用代碼連接MySQL數據庫,以及進行數據添加
Makefile文件如下:
PROJECT_ROOT = $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) # PROJECT_ROOT = /root/eclipse-workspace/mysql_c_demo/ # 中間文件, $(PROJECT_ROOT)*.o OBJS = mysql_c_demo.o MySQLManager.o # 目標文件名 TARGET = mysql_c_demo # 編譯器設置 CXXFLAGS += -std=c++17 -flto # 頭文件路徑 INCLUDE = -I$(PROJECT_ROOT)include/mysql # 鏈接庫路徑 LDFLAGS = -L$(PROJECT_ROOT)lib # 鏈接庫名 LIBS = -lmysqlclient -lpthread -lz -lm -lrt -lssl -lcrypto -ldl # 指定運行時的動態庫文件路徑 #RPATH = -Wl,-rpath=../lib # 宏定義 # DEFS = -NO_USE_SSL # debug or release設置 ifeq ($(BUILD_MODE),debug) CXXFLAGS += -g else ifeq ($(BUILD_MODE),run) CXXFLAGS += -O3 else $(error Build mode $(BUILD_MODE) not supported by this Makefile) endif all: $(TARGET) # 此處 $@ 表示目標文件集,即iot_servers, $^表示目標依賴集,即$(OBJS) mysql_c_demo: $(OBJS) $(CXX) -o $@ $^ $(LDFLAGS) $(LIBS) $(RPATH) # %.o表 示所有以.o結尾的文件,%.cpp 表示所有以.cpp結尾的文件 # $@ 表示目標集,也就是*.o文件,$< 表示所有的依賴目標集,即*.c文件(見Makefile自動化變量部分) %.o: $(PROJECT_ROOT)%.cpp $(CXX) -c $(CXXFLAGS) $(INCLUDE) -o $@ $< .PHONY: clean clean: rm -fr mysql_c_demo $(OBJS)
該文件為eclipse項目生成,其中有些變量在普通環境下不存在,刪掉或寫成自己的路徑即可。
三、問題
C API 默認使用 openssl 1.0版本,而我的項目中其他庫必須依賴openssl 1.1版本,導致無法鏈接進去(TMD),所以又改用 Connector/C++。
四、 Connector/C++
如下是使用JDBC API的例子
參考:
#include <mysql/jdbc.h> #include <iostream> using namespace std; int main(int argc, char **argv) { // 驅動 sql::mysql::MySQL_Driver *driver = nullptr; // 連接 sql::Connection *con = nullptr; // 數據庫操作執行對象 sql::Statement *state = nullptr; // 結果對象 sql::ResultSet *result = nullptr; // 初始化驅動 driver = sql::mysql::get_mysql_driver_instance(); if (driver == nullptr) { cout << "driver is null" << endl; } // 建立連接 con = driver->connect("tcp://127.0.0.1:3306", "root", "JiXiaohua@5712"); if (con == NULL) { cout << "conn is null" << endl; return -1; } cout << "connect suceess" << endl; // 創建數據庫操作執行對象 state = con->createStatement(); // use database state->execute("use c_mysql_test"); // 執行查詢 // 查詢 result = state->executeQuery("select * from u_test where 1=1"); // 輸出查詢 cout << "id" << "\t\t" << "name" << "\t\t" << "age" << "\t\t" << "comment" << endl; while(result->next()) { int id = result->getInt("id"); string name = result->getString("name"); int age = result->getInt("age"); string comment = result->getString("comment"); cout << id << "\t\t" << name << "\t\t" << age << "\t\t" << comment << endl; } // 釋放對象 delete state; delete con; return 0; }
完全的Java jdbc風格。
JDBC API的依賴庫太大了,官方文檔說了還可以使用X DevAPI and X DevAPI for C。