C++ MySQL连接及增删改查操作

一、使用准备

环境: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: 可以从 YumAPTSuSE 仓库获得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 --libsldd 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数据库,以及进行数据添加

[2] C++实现对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的例子

参考:

官方文档

MySql Connector/C++8简介

使用Connector/C++操作MySQL

MySQL connector/C++

#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。

 

posted @ 2020-05-08 18:24  jixhua  阅读(2760)  评论(0编辑  收藏  举报