相关推荐recommended
【MySQL】C语言连接MySQL
作者:mmseoamin日期:2024-01-30

文章目录

  • 一、引入库
    • 下载库文件
    • 验证是否引入成功
    • 二、MySQL C API相关接口
    • 三、总结

      一、引入库

      mysql的基础,我们之前已经学过,后面我们只关心使用要 使用C语言连接mysql ,需要使用mysql官网提供的库,大家可以去MySQL官网下载。

      下载库文件

      首先,进入MySQL官网,选择 DOWNLOADS, 然后点击 MySQL Community (GPL) Downloads 。如下:

      【MySQL】C语言连接MySQL,在这里插入图片描述,第1张

      【MySQL】C语言连接MySQL,在这里插入图片描述,第2张

      因为我们要使用C语言连接MySQL,所以这里选择 C API (libmysqlclient)。如下:

      【MySQL】C语言连接MySQL,在这里插入图片描述,第3张

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

      【MySQL】C语言连接MySQL,在这里插入图片描述,第4张

      上传到云服务器

      【MySQL】C语言连接MySQL,在这里插入图片描述,第5张

      进入解压目录后,可以看到有一个include子目录和一个lib子目录。如下:

      【MySQL】C语言连接MySQL,在这里插入图片描述,第6张


      当然我们可以通过yum来直接安装mysql client 以及 mysql devel,因为之前我们在安装mysql-commun-server时已经配置了mysql相关的yum源了。

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

      安装完毕后我们就可以在 /usr/include/mysql 目录下找到mysql相关的头文件了。

      【MySQL】C语言连接MySQL,在这里插入图片描述,第7张

      同时,我们也可以在 /lib64/mysql /以及 /usr/lib64/mysql 目录下找到mysql对应的动态库以及静态库了。

      【MySQL】C语言连接MySQL,在这里插入图片描述,第8张


      验证是否引入成功

      现在,我们就可以通过mysql目录下头文件中提供的相关函数来连接数据库了。

      这里我们可以通过mysql_get_client_info()函数来验证一下mysql相关头文件以及动态库是否被成功引入。

      #include 
      #include 
      using namespace std;
      int main()
      {
      	cout << "MySQL Client Version:" << mysql_get_client_info() << endl;
      	return 0;
      }
      
      # -L:指明库文件的所在路径
      # -l:指明所要链接的库
      test:test.cc
      	g++ -o $@ $^  -std=c++11 -L/lib64/mysql -lmysqlclient
      .PHONY:clean
      clean:
      	rm -f test
      

      这里说明一下:

      • -I:用于指明头文件的搜索路径。
      • -L:用于指明库文件的搜索路径。
      • -l:用于指明需要连接库文件路径下的哪一个库。

      【MySQL】C语言连接MySQL,在这里插入图片描述,第9张

      这里有几个需要注意的地方:

      • 由于我们要使用的mysql C库中的函数,所以在test.cc中我们需要包含mysql相关的头文件。
      • 在程序编译时,我们需要使用-I 选项来指定我们要链接的mysql动态库,并且动态库的库名称是去掉前缀lib以及后缀.so后的剩余部分。(libmysqlclient.so -> mysqlclient)
      • 由于动态库在 /usr/lib64/mysql/ 目录下,而系统默认库路径是 /usr/lib64/,所以我们还需要使用 -L选项来指定动态库的路径。
      • mysql C语言相关头文件在 /usr/include/mysql/ 目录下,而系统默认的头文件搜索路径是 /usr/include/,所以按道理来说,我们也是需要使用 -I 选项来指明头文件路径的。但这里由于我们在编写源程序,包含头文件时使用的是 mysql/mysql.h,而不仅仅是mysql.h,所以不需要指定。

        二、MySQL C API相关接口

        初始化MySQL

        要使用库,必须先进行初始化。mysql_init 函数会给我们返回一个 MYSQL 句柄,我们后续的操作都需要通过这个 MYSQL 句柄来完成。使用方法如下:

        MYSQL *m= mysql_init(nullptr); // 函数返回值:失败返回 NULL
        

        mysql_init 函数的参数以及返回值都是 MYSQL 指针类型,对于 MYSQL,大家把它类比到C语言中的文件指针来理解即可。MYSQL 和C语言文件 FILE 一样,本质上都是一个结构体。

        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;
          //...
          char *info_buffer;
          void *extension;
        } MYSQL;
        

        【MySQL】C语言连接MySQL,在这里插入图片描述,第10张

        连接MySQL

        初始化完毕后,我们需要使用 mysql_real_connect 函数来连接数据库。

        MYSQL *
        mysql_real_connect(MYSQL *mysql,       // MYSQL结构体指针对象
                           const char *host,   // mysqld服务进程所在的主机
                           const char *user,   // 登录MySQL的用户
                           const char *passwd, // 用户密码
                           const char *db,     // 要访问的数据库
                           unsigned int port,  // mysqld服务进程的端口号
                           const char *unix_socket,    // 默认设为NULL即可
                           unsigned long client_flag)  // 默认设为0即可
        // 函数返回值:失败返回0,成功返回传入的MYSQL指针
        

        【MySQL】C语言连接MySQL,在这里插入图片描述,第11张

        设置连接字符集

        我们之前在创建数据库时默认使用的字符集是 utf8,而C语言连接数据时默认的字符集是 latin1 的,这就会导致我们在向表中插入中文数据时,由于字符集不匹配,最终数据库中存储的数据显式出来是乱码。

        所以,我们需要使用 mysql_set_character_set 函数设置连接字符集为 utf8。

        int mysql_set_character_set(MYSQL *mysql, const char *csname)
        // 函数返回值:返回0表示成功,非0表示失败
        
        int n = mysql_set_character_set(mfp, "utf8");
        if(n != 0) { cout << "warning: character set fail" << endl; }
        

        下发mysql指令

        在成功连接到数据库之后,我们就可以通过 mysql_query 函数来下发 mysql 指令了。

        int mysql_query(MYSQL *mysql, const char *stmt_str)
        // 函数返回值:执行成功返回0,失败返回非0
        
        string sql;
        while (true)
        {
        	cout << "mysql>>> ";
        	getline(cin, sql);
        	int n = mysql_query(mfp, sql.c_str());
        	if (n != 0)
        	{
        		cout << sql << " fail" << endl;
        	}
        	else
        		cout << sql << " success" << endl;
        }
        

        【MySQL】C语言连接MySQL,在这里插入图片描述,第12张

        需要注意的是,我们在使用 mysql client 时,一条 sql 语句需要以分号结尾;但是在C语言中,sql 语句可以不用带分号,当然带上也没事。

        获取mysql查询结果

        我们上面是对数据库执行增删改操作,它们相对来说比较简单,因为我们只需要将指令下发给数据库即可,后面的事情我们不必关心。但如果我们执行的是查询操作,则需要通过 mysql_store_result 函数来获取查询结果。

        MYSQL_RES *mysql_store_result(MYSQL *mysql)
        // 函数返回值:失败返回 NULL,成功返回一个非空的 MYSQL_RES 类型的结构体指针
        

        实际上,mysql_store_result 函数会调用 MYSQL 结构体变量中的 st_mysql_methods 字段中的 read_rows 函数指针来获取查询的结果;然后将查询结果保存到 MYSQL_RES 结构体中并返回结构体指针。这样,当执行完 mysql_store_result 以后,其实数据都已经在MYSQL_RES 变量中了,我们直接从中获取即可。

        需要注意的是,MYSQL_RES 是通过 malloc/new 空间的方式来保存查询结果的,所以当我们使用完毕之后,一定要记得释放 MYSQL_RES 对象,否则就会造成内存泄漏。同时,MYSQL_RES 结构体中存在查询结果的列数、列信息、行数、行内容等属性,我们需要使用对应的函数来获取这些信息。

        获取结果列数

        unsigned int mysql_num_fields(MYSQL_RES *result)
        

        获取结果中每一列的列属性

        MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *res);
        

        关于 MYSQL_FIELD 结构体,它里面包含了列的各种属性信息,包括列名称、列类型、列大小、列属于哪个表哪个库等等。

        【MySQL】C语言连接MySQL,在这里插入图片描述,第13张

        同时,我们可以通过重复调用 mysql_fetch_field 函数来获取表中每个列字段的 MYSQL_FIELD 结构,即当我们下次再调用 mysql_fetch_field 函数时,会自动获取到表中下一个列的属性信息,而不需要我们手动指定访问的是哪一列。这和C++中的迭代器很类似。 这种类似迭代器的功能应该是与 MYSQL_RES 中的 current_field 字段有关。

        【MySQL】C语言连接MySQL,在这里插入图片描述,第14张

        当然,我们也可以通过调用 mysql_fetch_fields 函数一次获取到所有列的属性信息,然后分别打印。

        MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *res);
        

        获取结果行数

        my_ulonglong mysql_num_rows(MYSQL_RES *result)
        

        获取结果中每一行的具体内容

        MYSQL_ROW mysql_fetch_row(MYSQL_RES *result)
        

        MYSQL_ROW 本质上其实是一个二级指针,我们可以把它当作一个一级指针数组来看待,数组中的每个元素都是一级指针。同时,由于 MYSQL_RES 中保存的是查询到的多行结果,所以我们可以将 MYSQL_RES 看作是一个二级指针数组,数组中的每个元素都是二级指针 (MYSQL_ROW)。

        【MySQL】C语言连接MySQL,在这里插入图片描述,第15张

        释放 MYSQL_RES 对象

        由于 MYSQL_RES 保存查询结果的空间是通过 malloc/new 得到的,所以当我们使用完毕后需要释放掉 MYSQL_RES 对象,防止内存泄露。

        void mysql_free_result(MYSQL_RES *result)
        
        mysql_free_result(res);
        

        关闭MySQL连接

        当我们使用完 MySQL 后,需要关闭 MySQL 之前建立的连接。

        void mysql_close(MYSQL *sock);
        
        mysql_close(mfp);
        

        MySQL其他操作

        除了上述这些操作外,MySQL C API 还支持事务、回滚等常见操作,感兴趣的同学可以了解一下。

        my_bool STDCALL mysql_autocommit(MYSQL * mysql, my_bool auto_mode);
        my_bool STDCALL mysql_commit(MYSQL * mysql);
        my_bool STDCALL mysql_rollback(MYSQL * mysql);
        

        三、总结

        使用 MySQL C API 连接数据库进行简单操作的步骤如下:

        1. 初始化 MYSQL 结构体指针 – mysql_init。
        2. 连接 MySQL – mysql_real_connect:需要指定数据库服务所在主机、端口以及登录mysql的用户和密码等信息。
        3. 下发 MySQL 指令 – mysql_query。
        4. 获取 MySQL 查询结果:将查询结果转储到 MYSQL_RES 中 – mysql_store_result,获取查询结果的行数 – mysql_num_rows,获取查询结果列数 – mysql_num_fields,获取单个/所有列字段的 MYSQL_FIELD 属性信息 – mysql_fetch_field/mysql_fetch_fields,获取查询结果单行的内容 (不包含属性行) – mysql_fetch_row。
        5. 释放 MYSQL_RES 对象 – mysql_free_result。
        6. 关闭 MySQL 连接 – mysql_close。

        整体代码

        #include 
        #include 
        #include 
        using namespace std;
        const string host = "127.0.0.1";
        const string user = "cjl";
        const string password = "Cjl1314520@@..";
        const string db = "test";
        unsigned int port = 3306;
        int main()
        {
        	// 验证C库是否引入成功
        	// cout << "mysql version: " << mysql_get_client_info() << endl;
        	// 初始化MySQL指针
        	MYSQL *mfp = mysql_init(nullptr);
        	if (mfp == nullptr)
        	{
        		cerr << "mysql init error" << endl;
        		return 1;
        	}
        	cout << "mysql init success" << endl;
        	// 连接数据库
        	if (mysql_real_connect(mfp, host.c_str(), user.c_str(), password.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
        	{
        		cerr << "mysql connection error: " << endl;
        		return 2;
        	}
        	cout << "mysql connection success!" << endl;
        	//设置连接字符集
        	int n = mysql_set_character_set(mfp, "utf8");
        	if (n != 0)
        	{
        		cout << "warning: character set fail" << endl;
        	}
        	// 下发mysql指令--查询
        	std:string sql = "select * from students";
            if(mysql_query(mfp, sql.c_str()) != 0)
            {
                cout<<"查询数据失败!"<
                cout<
            //     cout << total_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<
        	// 	cout << "mysql>>> ";
        	// 	getline(cin, sql);
        	// 	int n = mysql_query(mfp, sql.c_str());
        	// 	if (n != 0)
        	// 	{
        	// 		cout << sql << " fail" << endl;
        	// 	}
        	// 	else
        	// 		cout << sql << " success" << endl;
        	// }
        	return 0;
        }