【MySQL数据库】:MySQL访问

目录

引入库

下载库文件 

在项目中使用库 

使用库

连接数据库

创建MySQL对象

 连接数据库

关闭数据库连接

连接示例

下发SQL请求

下发SQL请求

设置编码格式

增加、删除、修改

向数据库中插入数据 

删除数据库中的数据

获取查询结果

获取查询结果

查询结果的行数

查询结果的列数

查询结果中的一行数据

查询示例


引入库

要使用C语言连接MySQL数据库,需要使用MySQL官网提供的库。

首先执行下面两两条命令

sudo yum install -y mysql-community-server
sudo yum install -y mysql-community-devel

下载库文件 

  1. 首先,进入MySQL官网下载(官网地址:MySQL :: MySQL Community Downloads
  2. 选择下载 MySQL Connector/C

因为我们是要使用C语言连接MySQL,所以这里选择MySQL Connector/C。如下: 

最后选择适合自己平台的 mysql connect库,然后点击下载就行了。

上传到云服务器 

因为我们下载的是Linux下使用的库文件,但是是下载在Windows下的,因此下载完毕后需要将其上传到云服务器。(找一个目录放置即可)

将刚才下载的库文件上传到云服务器

rz -E

​ 将压缩包解压到当前目录下

tar -xzf mysql-connector-c-6.1.11-linux-glibc2.12-x86_64.tar.gz

将解压后的目录名称改短一点

mv mysql-connector-c-6.1.11-linux-glibc2.12-x86_64 mysql-connector

进入解压后 mysql-connector 的目录当中,可以看到有一个 include 子目录和一个lib子目录 

  1. include目录下存放的一堆头文件
  2. lib目录下存放的就是动静态库

在项目中使用库 

我们来做一个简单的小实验

  1. 创建一个 MysqlTest 项目目录
  2. 在项目目录下创建两个软连接,分别连接到刚才的include目录和lib目录
  3. 验证库是否引入成功
// 创建一个 MysqlTest 项目目录
mkdir MysqlTest
cd MysqlTest

// 在项目目录下创建两个软连接,分别连接到刚才的include目录和lib目录
ln -s /home/wh/Linux/mysql/mysql-connector/include include
ln -s /home/wh/Linux/mysql/mysql-connector/lib lib

这时直接在项目目录下,就能看到刚才include和lib目录下的内容 

​ 验证库是否引入成功

// test.cpp 文件
#include <iostream>
#include <mysql.h>
using namespace std;

int main()
{
    //获取客户端的版本信息
    cout<<"mysql client version: "<< mysql_get_client_info() << endl;

    return 0;
}
// Makefile 文件
test:test.cpp
	g++ -o $@ $^ -I./include -L./lib -lmysqlclient
.PHNOY:clean
clean:
	rm -f test
  • -I:用于指明头文件的搜索路径。
  • -L:用于指明库文件的搜索路径。
  • -l:用于指明需要连接库文件路径下的哪一个库。

编译上方程序,并且执行程序,发现无法运行

我们根据错误信息看到该可执行程序所依赖的mysqlclient 库找不到,查看共享库依赖关系 

ldd mysql_connect

为什么会出现这样的错误呢? 我们在编译的时候不是已经说明了吗?

  1. gcc/g++ 编译器默认都是动态链接的,编译代码时默认使用的是动态库,所以生成的可执行程序在运行时需要找到对应的动态库进行链接,而我们使用的 mysqlclient 库并不在系统的搜索路径下。
  2. 需要注意的是,Makefile中的-I,-L和-l这三个选项,只是在编译期间告诉编译器头文件和库文件在哪里,而可执行程序生成后就与编译器无关了。

动态链接是程序运行时将程序模块与主程序进行链接的过程。而动态库是包含可共享代码和数据的文件,是动态链接过程中被链接的对象。

我们应该如何去解决呢?

  1. 将库文件拷贝到系统默认的库文件搜索路径下/lib64
  2. 将库文件所在的目录路径添加到LD_LIBRARY_PATH环境变量中,该环境变量可以用于指定查找动态库时的其他路径。
  3. 将库文件所在的目录路径保存到以.conf为后缀的配置文件中,然后将该文件拷贝到 /etc/ld.so.conf.d 目录下,并使用 ldconfig 命令对配置文件进行更新,该目录下所有配置文件中的路径也将作为查找动态库时的搜索路径。

建议使用第三种方法,其他两种都具有安全隐患

echo /home/wh/MysqlTest/lib > mysql_connect.conf
sudo cp mysql_connect.conf /etc/ld.so.conf.d
ls /etc/ld.so.conf.d
sudo ldconfig

此时该可执行程序所依赖的mysqlclient库就能够被找到了 

​ 

使用库

至此库已经成功被引入,剩下就是库接口的使用问题了。

连接数据库

创建MySQL对象

创建MySQL对象的函数如下:

MYSQL* mysql_init(MYSQL *mysql);

参数返回值:

  • 该函数用来分配或者初始化一个MySQL对象,用于连接MySQL服务器。
  • 如果传入的参数是NULL,那么mysql_init将自动为你分配一个MySQL对象并返回。
  • 如果传入的参数是一个地址,那么mysql_init将在该地址处帮你完成初始化。

MYSQL对象中包含了各种信息,其类型定义如下:

typedef struct st_mysql {
	NET net;			/* Communication parameters */
    unsigned char	*connector_fd;		/* ConnectorFd for SSL */
    char *host,*user,*passwd,*unix_socket,*server_version,*host_info;
    char *info, *db;
    struct charset_info_st *charset;
    MYSQL_FIELD	*fields;
    MEM_ROOT field_alloc;
    my_ulonglong affected_rows;
    my_ulonglong insert_id;		/* id if insert on table with NEXTNR */
    my_ulonglong extra_info;		/* Not used */
    unsigned long thread_id;		/* Id for connection in server */
    unsigned long packet_length;
    unsigned int port;
    unsigned long client_flag,server_capabilities;
    unsigned int protocol_version;
    unsigned int field_count;
    unsigned int server_status;
    unsigned int server_language;
    unsigned int warning_count;
    struct st_mysql_options options;
    enum mysql_status status;
    my_bool	free_me;		/* If free in mysql_close */
    my_bool	reconnect;		/* set to 1 if automatic reconnect */

    /* session-wide random string */
    char scramble[SCRAMBLE_LENGTH+1];
    my_bool unused1;
    void *unused2, *unused3, *unused4, *unused5;

    LIST *stmts;                     /* list of all statements */
    const struct st_mysql_methods *methods;
    void *thd;
    /*
      Points to boolean flag in MYSQL_RES  or MYSQL_STMT. We set this flag
      from mysql_stmt_close if close had to cancel result set of this object.
    */
    my_bool *unbuffered_fetch_owner;
    /* needed for embedded server - no net buffer to store the 'info' */
    char *info_buffer;
    void *extension;
} MYSQL;

 连接数据库

MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, 
                          const char *user, const char *password, 
                          const char *db, unsigned int port, 
                          const char *unix_socket, unsigned long client_flag);

参数说明: 

  1. mysql:这是一个MYSQL类型的指针。它是一个已经初始化的MYSQL结构的指针,这个结构用于存储连接相关的信息。通常先使用mysql_init函数初始化一个MYSQL结构,然后将其指针传递给mysql_real_connect
  2. host:一个字符串,用于指定 MySQL 服务器的主机名或者 IP 地址。例如,"localhost"表示连接本地的 MySQL 服务器,"192.168.1.100"则表示连接指定 IP 地址的服务器。
  3. user:也是一个字符串,代表用于登录 MySQL 数据库的用户名。比如"root"是 MySQL 中常见的超级用户账户。
  4. password:字符串类型,是与user对应的用户密码。
  5. db:字符串参数,用于指定要连接的数据库名称。如果不需要连接特定数据库(只是想连接到服务器进行一些如创建数据库等操作),可以将这个参数设置为NULL
  6. port:一个无符号整数,用于指定 MySQL 服务器的端口号。默认的 MySQL 端口是 3306,如果 MySQL 服务器运行在默认端口,这个参数可以设置为 0 或者MYSQL_PORT(在 MySQL 头文件中有定义)。
  7. unix_socket:在 Unix - like 系统中,这是一个字符串,用于指定连接 MySQL 服务器的 Unix 套接字文件路径。如果不使用套接字连接,可以将这个参数设置为NULL。在 Windows 系统中,这个参数通常被忽略。
  8. client_flag:一个无符号长整数,用于设置客户端连接的各种标志。例如,可以通过这个参数指定是否使用 SSL 连接等选项。常见的标志有CLIENT_FOUND_ROWS(返回找到的行数而不是受影响的行数)、CLIENT_COMPRESS(使用压缩协议)等。如果不需要特殊的连接标志,可以将这个参数设置为 0。

返回值说明:

  1. 如果连接数据库成功,则返回一个MySQL对象,该对象与第一个参数的值相同。
  2. 如果连接数据库失败,则返回NULL。

关闭数据库连接

void mysql_close(MYSQL *sock);
  • 该函数的参数,就是连接数据库前调用mysql_init创建的MySQL对象。
  • 如果传入的MySQL对象是mysql_init自动创建的,那么调用mysql_close时就会释放这个对象。

连接示例

使用如下代码连接我的MySQL服务器:

#include <iostream>
#include <mysql/mysql.h>
#include <string>

using namespace std;

const string host = "localhost";
const string user = "wh";
const string passwd = "123456789";
const string db = "Test1";
const int port = 3306;

int main()
{
    //1、创建MySQL对象
    MYSQL* ms = mysql_init(nullptr);

    //2、连接数据库
    if(nullptr == mysql_real_connect(ms, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0))
    {
        cerr<<"数据库连接失败!"<<endl;
        return 1;
    }
    cout<<"数据库连接成功!"<<endl;

    //3、关闭数据库
    mysql_close(ms);
    cout<<"数据库关闭成功!"<<endl;
    return 0;
}

下发SQL请求

下发SQL请求

我们与数据库建立连接期间,就可以向MySQL服务器下发SQL请求,下发SQL请求的函数如下:

int	mysql_query(MYSQL *mysql, const char *q);

参数:

  • mysql:这是一个MYSQL *类型的指针,指向已经建立连接的 MySQL 数据库对象。这个连接对象是通过mysql_real_connect函数成功建立连接后返回的。
  • query:是一个字符串常量或字符数组,用于存放要执行的 SQL 语句。例如:const char *sql_query = "SELECT * FROM users";。这个 SQL 语句需要遵循 MySQL 的语法规则,并且要根据具体的数据库结构和需求来编写。

返回值:

  • 如果 SQL 语句执行成功,对于非SELECT语句(如INSERTUPDATEDELETE等操作语句),函数返回 0。这表示数据库已经成功地执行了请求的操作,例如成功插入了一条记录、更新了数据或者删除了指定的数据。
  • 对于SELECT语句,如果执行成功,函数也返回 0。但需要注意的是,这并不意味着已经获取到了查询结果,只是表示查询请求已经成功发送到数据库,还需要使用其他函数(如mysql_store_resultmysql_use_result)来获取和处理查询结果。
  • 如果 SQL 语句执行失败,函数返回非零值。可以通过mysql_error函数来获取具体的错误信息,以帮助定位和解决问题。
  • if (mysql_query(conn, sql_query)) 
    {
        fprintf(stderr, "SQL query error: %s\n", mysql_error(conn));
        // 进行错误处理,如返回错误码、退出程序等
    }

设置编码格式

在连接数据库之后,需要统一客户端和服务器的编码格式,避免在数据交互过程中出现乱码,设置编码格式的函数如下:

int mysql_set_character_set(MYSQL *mysql, const char *csname);

参数说明:

  • mysql: 表示在连接数据库前,调用mysql_init函数创建的MySQL对象。
  • csname: 表示要设置的编码格式,如"utf8"

返回值说明:

  • 返回值为0表示设置成功,否则表示设置失败。

增加、删除、修改

我们来做一个简单的小测试

使用的是一个 main 的测试表 ,里面没有任何数据

向数据库中插入数据 
// 正常在终端
insert into main values (1,'鱼丸',26);
#include <iostream>
#include <mysql/mysql.h>
#include <string>

using namespace std;

const string host = "localhost";
const string user = "wh";
const string passwd = "123456789";
const string db = "Test1";
const int port = 3306;

int main()
{
    //1、创建MySQL对象
    MYSQL* ms = mysql_init(nullptr);
    //2、连接数据库
    if(mysql_real_connect(ms, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        cerr<<"数据库连接失败!"<<endl;
        return 1;
    }
    cout<<"数据库连接成功!"<<endl;
    mysql_set_character_set(ms, "utf8"); //设置编码格式为utf8
    
    //3、向数据库表中插入记录
    std:string sql = "insert into main values (1,'鱼丸',26)";
    if(mysql_query(ms, sql.c_str()) != 0)
    {
        cout<<"插入数据失败!"<<endl;
        return 2;
    }
    cout<<"插入数据成功!"<<endl;

    //4、关闭数据库
    mysql_close(ms);
    cout<<"数据库关闭成功!"<<endl;
    return 0;
}

 

删除数据库中的数据
// 正常在终端
delete from main where id=1

 

#include <iostream>
#include <mysql/mysql.h>
#include <string>

using namespace std;

const string host = "localhost";
const string user = "wh";
const string passwd = "123456789";
const string db = "Test1";
const int port = 3306;

int main()
{
    //1、创建MySQL对象
    MYSQL* ms = mysql_init(nullptr);
    //2、连接数据库
    if(mysql_real_connect(ms, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        cerr<<"数据库连接失败!"<<endl;
        return 1;
    }
    cout<<"数据库连接成功!"<<endl;
    mysql_set_character_set(ms, "utf8"); //设置编码格式为utf8
    
     //3、删除数据库表中的记录
    std:string sql = "delete from main where id=1";
    if(mysql_query(ms, sql.c_str()) != 0)
    {
        cout<<"删除数据失败!"<<endl;
        return 2;
    }
    cout<<"删除数据成功!"<<endl;


    //4、关闭数据库
    mysql_close(ms);
    cout<<"数据库关闭成功!"<<endl;
    return 0;
}

获取查询结果

  • 对数据库中的数据进行增删改操作时,都只需要调用 mysql_query 向服务器下发对应的SQL请求。
获取查询结果
MYSQL_RES* mysql_store_result(MYSQL *mysql);
  • 该函数会调用指定MySQL对象中对应的函数指针来获取查询结果,并将获取到的查询结果保存到MYSQL_RES变量中进行返回。
  • 需要注意的是,MYSQL_RES变量的内存空间是malloc出来的,因此在使用完后需要调用free函数进行释放,否则会造成内存泄露。

MYSQL_RES变量中保存了查询得到的各种信息,其类型定义如下:

typedef struct st_mysql_res {
	my_ulonglong  row_count;
	MYSQL_FIELD	*fields;
	MYSQL_DATA	*data;
	MYSQL_ROWS	*data_cursor;
	unsigned long *lengths;		/* column lengths of current row */
	MYSQL		*handle;		/* for unbuffered reads */
    const struct st_mysql_methods *methods;
    MYSQL_ROW	row;			/* If unbuffered read */
    MYSQL_ROW	current_row;		/* buffer to current row */
    MEM_ROOT	field_alloc;
    unsigned int	field_count, current_field;
    my_bool	eof;			/* Used by mysql_fetch_row */
    /* mysql_stmt_close() had to cancel this result */
    my_bool       unbuffered_fetch_cancelled;
    void *extension;
} MYSQL_RES;
查询结果的行数

获取查询结果的行数的函数

my_ulonglong mysql_num_rows(MYSQL_RES *res);
  • 该函数将会从指定的MYSQL_RES对象中,获取查询结果的行数。

 

查询结果的列数

获取查询结果的列数的函数

unsigned int mysql_num_fields(MYSQL_RES *res);
  • 该函数将会从指定的MYSQL_RES对象中,获取查询结果的列数。

mysql_fetch_fields函数将会返回多个MYSQL_FIELD对象,每个MYSQL_FIELD对象中保存着对应列的各种列属性,其类型定义如下:

typedef struct st_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;
查询结果中的一行数据

获取查询结果中的一行数据的函数

MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
  • 该函数将会从指定的MYSQL_RES对象中,获取查询结果中的一行数据。

MYSQL_ROW对象中保存着一行数据,这一行数据中可能包含多个字符串,对应就是这行数据中的多个列信息,因此MYSQL_ROW本质就是char**类型,其类型定义如下:

typedef char **MYSQL_ROW;		/* return data as array of strings */
查询示例
#include <iostream>
#include <mysql/mysql.h>
#include <string>

using namespace std;

const string host = "localhost";
const string user = "wh";
const string passwd = "123456789";
const string db = "Test1";
const int port = 3306;

int main()
{
    //1、创建MySQL对象
    MYSQL* ms = mysql_init(nullptr);
    //2、连接数据库
    if(mysql_real_connect(ms, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        cerr<<"数据库连接失败!"<<endl;
        return 1;
    }
    cout<<"数据库连接成功!"<<endl;
    mysql_set_character_set(ms, "utf8"); //设置编码格式为utf8
    
    //3、查询数据库表中的记录
    //a、执行查询语句
    std:string sql = "select * from main";
    if(mysql_query(ms, sql.c_str()) != 0)
    {
        cout<<"查询数据失败!"<<endl;
        return 2;
    }
    cout<<"查询数据成功!"<<endl;
    //b、获取查询结果
    MYSQL_RES* res = mysql_store_result(ms);
    int rows = mysql_num_rows(res); //数据的行数
    int cols = mysql_num_fields(res); //数据的列数
    //获取每列的属性并打印列名
    MYSQL_FIELD* fields = mysql_fetch_fields(res);
    for(int i = 0;i < cols;i++)
    {
        cout<<fields[i].name<<"\t";
    }
    cout<<endl;
    for(int i = 0;i < rows;i++)
    {
        //获取一行数据并进行打印
        MYSQL_ROW row = mysql_fetch_row(res);
        for(int j = 0;j < cols;j++)
        {
            cout<<row[j]<<"\t";
        }
        cout<<endl;
    }
    free(res); //释放内存空间


    //4、关闭数据库
    mysql_close(ms);
    cout<<"数据库关闭成功!"<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-元清-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值