MySQL连接(十四)

MySQL库的引入

我们使用C接口库来进行连接,要正确使用,我们需要做一些准备工作:引入MySQL库

第一种方法:手动从 MySQL 官网下载源码 / 预编译包,自行制作 / 配置库

使用mysql官网提供的库,去官网下载。

预编译版 .tar.gz 包 :可以直接解压使用(无需编译)

这种包是官方已经在对应 Linux 架构(如 x86_64)下编译好的成品,解压后直接包含 include(头文件)、lib(库文件)、bin(可执行文件)目录,无需再执行 cmake 编译流程,直接拷贝到目标目录即可使用。

具体步骤:

  1. 下载对应架构的预编译 .tar.gz 包后,解压到自定义目录:
bash 复制代码
# 解压预编译包到 /usr/local 目录(系统级目录,方便后续引用)
sudo tar -zxvf mysql-connector-c-8.0.36-linux-glibc2.28-x86_64.tar.gz -C /usr/local/
  1. 重命名目录,方便后续引用
bash 复制代码
sudo mv /usr/local/mysql-connector-c-8.0.36-linux-glibc2.28-x86_64 /usr/local/mysql-c-api
  1. 验证解压结果:进入目录后,能看到完整的 include 和 lib 目录,说明可以直接使用:
bash 复制代码
# 查看目录结构
ls /usr/local/mysql-c-api/
# 预期输出:bin  include  lib  LICENSE  man  README
  1. 编译 C 程序时,手动指定头文件和库文件路径即可
bash 复制代码
gcc mysql_test.c -o mysql_test \
-I/usr/local/mysql-c-api/include \  # 指定头文件路径
-L/usr/local/mysql-c-api/lib \      # 指定库文件路径
-lmysqlclient                       # 链接mysql客户端库

当然也可以放到系统的头文件目录和库目录,编译时就不用指定头文件路径和库文件路径了。

注意:如果下载的是源码包(后缀为 .tar.gz),需要手动编译安装(依赖 gcc、cmake 环境,需提前安装)。

第二种方法:Linux(Ubuntu)下通过 apt 命令自动下载安装(最简单)

bash 复制代码
# 更新软件源
sudo apt update
# 核心命令:安装mysql客户端库和开发文件(头文件+库文件)
sudo apt install libmysqlclient-dev -y

安装完成后,系统会自动将头文件和库文件放到默认路径:

  • 头文件:/usr/include/mysql/(包含 mysql.h 等核心头文件)
  • 库文件:/usr/lib/x86_64-linux-gnu/(包含 libmysqlclient.so 等动态库、libmysqlclient.a 静态库)
    无需手动配置路径,编译 C 程序时直接链接即可。

测试

通过 mysql_get_client_info() 函数,来验证我们的引入是否成功

cpp 复制代码
#include <iostream>
#include <mysql/mysql.h>

int main()
{
    std::cout << "mysql client version: " << mysql_get_client_info() << std::endl;
    return 0;
}

syb@VM-8-5-ubuntu:~/mysqltest$ g++ -o mytest test.cc -lmysqlclient 
syb@VM-8-5-ubuntu:~/mysqltest$ ./mytest 
mysql client version: 8.0.44                           --运行成功

至此引入库的工作已经做完,接下来就是熟悉接口

mysql接口介绍

官方文档:www.mysql.com

找到C接口的文档

文档介绍

初始化mysql_init()

要使用库,必须先进行初始化。

cpp 复制代码
MYSQL *mfp = mysql_init(nullptr)

关闭mysql链接mysql_close

cpp 复制代码
void mysql_close(MYSQL *sock);
cpp 复制代码
int main()
{
    MYSQL *my = mysql_init(nullptr);
    if(nullptr == main)
    {
        std::cerr << "init MySQL error" << std::endl;
        return 1;
    }
    mysql_close(my);
    return 0;
}

链接数据库mysql_real_connect()

初始化完毕之后,必须先链接数据库,在进行后续操作。(mysql网络部分是基于TCP/IP的)

cpp 复制代码
MYSQL *mysql_real_connect(MYSQL *mysql,     		//初始化创建的句柄
                          const char *host, 		//用户IP
                          const char *user,			//登录的用户
                          const char *passwd,		//用户密码
                          const char *db,			//用户访问的数据库
                          unsigned int port,		//端口号
                          const char *unix_socket,
                          unsigned long clientflag);
//建立好链接之后,获取英文没有问题,如果获取中文是乱码:
//设置链接的默认字符集是utf8,原始默认是latin1
mysql_set_character_set(myfd, "utf8");

第一个参数 MYSQL是 C api中一个非常重要的变量(mysql_init的返回值),里面内存非常丰富,有port,dbname,charset等连接基本参数。它也包含了一个叫 st_mysql_methods的结构体变量,该变量里面保存着很多函数指针,这些函数指针将会在数据库连接成功以后的各种数据操作中被调用。

例子:

cpp 复制代码
#include <iostream>
#include <string>
#include <mysql/mysql.h>

const std::string host = "127.0.0.1";
const std::string user = "connector";
const std::string passwd = "123456";
const std::string db = "conn";
const unsigned int port = 3306;//mysqld启动的默认端口是3306,所以连接也用这个

int main()
{
    MYSQL *my = mysql_init(nullptr);
    if (nullptr == my)
    {
        std::cerr << "init MySQL error" << std::endl;
        return 1;
    }

    if(mysql_real_connect(my,host.c_str(),user.c_str(),passwd.c_str(),db.c_str(),port,nullptr,0)==nullptr)
    {
        std::cerr << "connect MySQL error" << std::endl;
        return 2;
    }
    std::cout <<"connect success"<<std::endl;
    mysql_close(my);
    return 0;
}

下发mysql命令mysql_query

cpp 复制代码
int mysql_query(MYSQL *mysql, const char *q);

第二个参数为要执行的sql语句,如"select * from table"。

返回值,成功返回0,失败返回非0。

例子:

cpp 复制代码
    std::string sql = " insert into user (name, age, telphone) values ('tom', 12, '123456789')";
    int n = mysql_query(my, sql.c_str());
    if (n == 0)
        std::cout << sql << std::endl;
    else
        std::cout << sql << "failed" << std::endl;
cpp 复制代码
#include <iostream>
#include <string>
#include <mysql/mysql.h>

const std::string host = "127.0.0.1";
const std::string user = "connector";
const std::string passwd = "syb020913";
const std::string db = "conn";
const unsigned int port = 3306; // mysqld启动的默认端口是3306,所以连接也用这个

int main()
{
    MYSQL *my = mysql_init(nullptr);
    if (nullptr == my)
    {
        std::cerr << "init MySQL error" << std::endl;
        return 1;
    }

    if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        std::cerr << "connect MySQL error" << std::endl;
        return 2;
    }
    std::cout << "connect success" << std::endl;
    // 建立好链接之后,获取英文没有问题,但是获取中文可能是乱码
    // 设置链接的默认字符集是utf8,原始默认是latin1
    mysql_set_character_set(my, "utf8");//这时候就可以向数据库插入中文了

    std::string sql;
    while (true)
    {
        std::cout << "MySQL>> ";
        if (!std::getline(std::cin, sql) || sql == "quit")
        {
            std::cout << "bye!" << std::endl;
            break;
        }

        int n = mysql_query(my, sql.c_str());
        if (n == 0)
        {
            std::cout << sql << " success: " << n << std::endl;
        }
        else
        {
            std::cerr << sql << " failed: " << n << std::endl;
        }
    }

    mysql_close(my);
    return 0;
}

获取执行结果mysql_store_result

sql执行完以后,如果是查询语句 ,我们当然还要读取数据,如果update,insert等语句,那么就看下操作成功与否即可。我们来看看如何获取查询结果: 如果mysql_query返回成功,那么我们就通过mysql_store_result这个函数来读取结果。原型如下:

cpp 复制代码
MYSQL_RES *mysql_store_result(MYSQL *mysql);

同时该函数会返回MYSQL_RES 这样一个变量,该变量主要用于保存查询的结果。

  • 成功返回MYSQL_RES指针
  • 失败返回null。

注意 :该函数malloc了一片内存空间来存储查询过来的数据,所以我们一定要记的 free(result) ,不然是肯定会造成内存泄漏的。

例子:

cpp 复制代码
MYSQL_RES *res = mysql_store_result(my);
if(nullptr == my)
{
    std::cerr<<"mysql_store_result error"<<std::endl;
    return 4;
}
mysql_free_result(res);//不要忘记释放

执行完mysql_store_result以后,其实数据都已经在MYSQL_RES 变量中了,下面的api基本就是读取MYSQL_RES 中的数据。

读取MYSQL_RES

获取结果行数mysql_num_rows

cpp 复制代码
my_ulonglong mysql_num_rows(MYSQL_RES *res);

获取结果列数mysql_num_fields

cpp 复制代码
unsigned int mysql_num_fields(MYSQL_RES *res);

获取结果内容mysql_fetch_row

cpp 复制代码
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);

它会返回一个MYSQL_ROW变量,MYSQL_ROW其实就是char**,当成二维数组使用就行。

关于MYSQL_RES 的结构

里面有个成员变量MYSQL_ROW,存储着查询结构的数据,本质上可以理解为一个二维数组,MYSQL_RES 维护一块开辟的空间,将MySQL输出的数据保存起来,全部当成字符串。

cpp 复制代码
MYSQL_ROW line;
for (int i = 0; i < nums; i++)
{
    line = mysql_fetch_row(res);
    for (int j = 0; j < fields; j++)
    {
        cout << line[j] << " ";
    }
    cout << endl;
}

例子:

cpp 复制代码
#include <iostream>
#include <string>
#include <mysql/mysql.h>

const std::string host = "127.0.0.1";
const std::string user = "connector";
const std::string passwd = "syb020913";
const std::string db = "conn";
const unsigned int port = 3306; // mysqld启动的默认端口是3306,所以连接也用这个

int main()
{
    MYSQL *my = mysql_init(nullptr);
    if (nullptr == my)
    {
        std::cerr << "init MySQL error" << std::endl;
        return 1;
    }

    if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        std::cerr << "connect MySQL error" << std::endl;
        return 2;
    }
    std::cout << "connect success" << std::endl;
    // 建立好链接之后,获取英文没有问题,但是获取中文可能是乱码
    // 设置链接的默认字符集是utf8,原始默认是latin1
    mysql_set_character_set(my, "utf8"); // 这时候就可以插入中文了

    // std::string sql = " insert into user (name, age, telphone) values ('tom', 12, '123456789')";
    std::string sql = "select * from user";
    int n = mysql_query(my, sql.c_str());
    if (n == 0)
        std::cout << sql << std::endl;
    else
    {
        std::cout << sql << "failed" << std::endl;
        return 3;
    }
//---------------------------------------------------------------------
    MYSQL_RES *res = mysql_store_result(my);
    if (nullptr == my)
    {
        std::cerr << "mysql_store_result error" << std::endl;
        return 4;
    }

    my_ulonglong rows = mysql_num_rows(res);
    my_ulonglong fields = mysql_num_fields(res);

    std::cout << "行:" << rows << std::endl;
    std::cout << "列:" << fields << std::endl;

    for (int i = 0; i < rows; i++)
    {
        MYSQL_ROW row = mysql_fetch_row(res);
        for (int j = 0; j < fields; j++)
        {
            std::cout << row[j] << "\t";
        }
        std::cout << std::endl;
    }
//------------------------------------------------------------------
	mysql_free_result(res);
    mysql_close(my);
    return 0;
}

//结果
syb@VM-8-5-ubuntu:~/mysqltest$ ./mytest 
connect success
select * from user
行:3
列:4
1       tom     12      123456789
2       peter   19      2145125324
3       张三    23      83294824

获取列名mysql_fetch_fields

cpp 复制代码
MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *res);

关于MYSQL_FIELD的结构

里面存储的是关于列的各种信息

cpp 复制代码
typedef struct MYSQL_FIELD {
  char *name;               /* Name of column */
  char *org_name;           /* Original column name, if an alias */
  char *table;              /* Table of column if column was a field */
  char *org_table;          /* Org table name, if table was an alias */
  char *db;                 /* Database for table */
  char *catalog;            /* Catalog for table */
  char *def;                /* Default value (set by mysql_list_fields) */
  unsigned long length;     /* Width of column (create length) */
  unsigned long max_length; /* Max width for selected set */
  unsigned int name_length;
  unsigned int org_name_length;
  unsigned int table_length;
  unsigned int org_table_length;
  unsigned int db_length;
  unsigned int catalog_length;
  unsigned int def_length;
  unsigned int flags;         /* Div flags */
  unsigned int decimals;      /* Number of decimals in field */
  unsigned int charsetnr;     /* Character set */
  enum enum_field_types type; /* Type of field. See mysql_com.h for types */
  void *extension;
} MYSQL_FIELD;

例子:

cpp 复制代码
#include <iostream>
#include <string>
#include <mysql/mysql.h>

const std::string host = "127.0.0.1";
const std::string user = "connector";
const std::string passwd = "syb020913";
const std::string db = "conn";
const unsigned int port = 3306; // mysqld启动的默认端口是3306,所以连接也用这个

int main()
{
    MYSQL *my = mysql_init(nullptr);
    if (nullptr == my)
    {
        std::cerr << "init MySQL error" << std::endl;
        return 1;
    }

    if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        std::cerr << "connect MySQL error" << std::endl;
        return 2;
    }
    std::cout << "connect success" << std::endl;
    // 建立好链接之后,获取英文没有问题,但是获取中文可能是乱码
    // 设置链接的默认字符集是utf8,原始默认是latin1
    mysql_set_character_set(my, "utf8"); // 这时候就可以插入中文了

    // std::string sql = " insert into user (name, age, telphone) values ('tom', 12, '123456789')";
    std::string sql = "select * from user";
    int n = mysql_query(my, sql.c_str());
    if (n == 0)
        std::cout << sql << std::endl;
    else
    {
        std::cout << sql << "failed" << std::endl;
        return 3;
    }

    MYSQL_RES *res = mysql_store_result(my);
    if (nullptr == my)
    {
        std::cerr << "mysql_store_result error" << std::endl;
        return 4;
    }

    my_ulonglong rows = mysql_num_rows(res);
    my_ulonglong fields = mysql_num_fields(res);

    std::cout << "行:" << rows << std::endl;
    std::cout << "列:" << fields << std::endl;
//-------------------------------------------------------------------------
    //列属性
    MYSQL_FIELD *fields_array = mysql_fetch_fields(res); 
    for(int i = 0;i<fields;i++)
    {
        std::cout << fields_array[i].name << "\t";
    }
    std::cout << std::endl;
//-------------------------------------------------------------------------
    //内容
    for (int i = 0; i < rows; i++)
    {
        MYSQL_ROW row = mysql_fetch_row(res);
        for (int j = 0; j < fields; j++)
        {
            std::cout << row[j] << "\t";
        }
        std::cout << std::endl;
    }
    mysql_free_result(res);
    mysql_close(my);
    return 0;
}

//结果
syb@VM-8-5-ubuntu:~/mysqltest$ ./mytest 
connect success
select * from user
行:3
列:4
id      name    age     telphone
1       tom     12      123456789
2       peter   19      2145125324
3       张三    23      83294824
相关推荐
m0_706653233 小时前
用Python创建一个Discord聊天机器人
jvm·数据库·python
渡我白衣4 小时前
【MySQL基础】(2):数据库基础概念
数据库·人工智能·深度学习·神经网络·mysql·机器学习·自然语言处理
alien爱吃蛋挞4 小时前
【JavaEE】万字详解Mybatis(上)
数据库·java-ee·mybatis
写代码的【黑咖啡】4 小时前
HiveSQL 语法详解与常用 SQL 写法实战
数据库·sql
黄筱筱筱筱筱筱筱4 小时前
7.适合新手小白学习Python的异常处理(Exception)
java·前端·数据库·python
怣504 小时前
MySQL WHERE子句完全指南:精准过滤数据的艺术
数据库·mysql
大鳥4 小时前
第一章 - 数据仓库是什么
大数据·数据库·hive
u0109272716 小时前
RESTful API设计最佳实践(Python版)
jvm·数据库·python
qq_1927798712 小时前
高级爬虫技巧:处理JavaScript渲染(Selenium)
jvm·数据库·python