数据库学习笔记(十九)--C/C++调用MYSQL接口



前言

  • 学习和使用数据库可以说是程序员必须具备能力,这里将更新关于MYSQL的使用讲解,大概应该会更新30篇左右,涵盖入门、进阶、高级(一些原理分析);

  • 👨‍🏫 内容: 这一篇讲解C/C++调用MYSQL的基本API使用,更详细请看github

  • 虽然MYSQL命令很多,但是自己去多敲一点,到后面忘记了,查一下就可以回忆起来使用了;

  • 这一系列也是本人学习MYSQL做的笔记,也是为了方便后面忘记查询;

  • 参考资料:黑马、csdn和知乎博客;

  • 欢迎收藏 + 关注,本人将会持续更新后端和AI算法的学习笔记。

    文章目录

MySQL 8.0 C API开发指南

1. C API基本接口

1.1 C API 基本数据结构

本节描述了用于准备语句、异步接口或复制流接口的 C API 数据结构。

  • MYSQL

    此结构表示一个数据库连接的处理程序。它用于几乎所有 MySQL 功能。不要尝试复制MYSQL结构。无法保证此类副本将可用。

  • MYSQL_RES

    **此结构表示返回行 ( SELECT, SHOW, DESC/DESCRIBE, EXPLAIN) 的查询的结果。**在本节的其余部分中,从查询返回的信息称为结果集

  • MYSQL_ROW

    这是一行数据的类型安全表示。它目前被实现为一个计数字节字符串的数组(char**)。通过调用 mysql_fetch_row() 获取行。

  • MYSQL_FIELD

    此结构包含元数据:有关字段的信息,例如字段的名称、类型和大小。 本节稍后将更详细地描述其成员。 您可以通过重复调用 mysql_fetch_field() 来获取每个字段的 MYSQL_FIELD 结构。 字段值不属于此结构; 它们包含在 MYSQL_ROW 结构中。

  • MYSQL_FIELD_OFFSET

    这是 MySQL 字段列表中偏移量的类型安全表示。 (由 mysql_field_seek() 使用。)偏移量是一行中的字段编号,从零开始。

1.2 C API基本流程

流程

基本流程

初始化------->连接------->断开连接

加强流程

初始化------->连接------->设置连接超时时长和设置断开重连------->连接------->关闭

头文件

c 复制代码
#include<stdio.h>
#include<mysql.h>

把mysql头文件包含到代码中。

初始化

c 复制代码
int main()
{
    //初始化MYSQL
    MYSQL* mycon = NULL;
    mycon = mysql_init(NULL);
    if(mycon == NULL)
    {
		printf("[error:%d]%s\n",mysql_errno(mycon),mysql_error(mycon));
        return -1;
    }

设置超时时长和断开重新连接

c 复制代码
int mysql_options(MYSQL *mysql, enum mysql_option option, const char *arg)

可用于设置额外的连接选项,并影响连接的行为 。可多次调用该函数来设置数个选项。应在mysql_init()之后、以及mysql_connect()或mysql_real_connect()之前调用mysql_options()。
第二个参数

c 复制代码
MYSQL_OPT_CONNECT_TIMEOUT  //unsigned int *        以秒为单位的连接超时。

MYSQL_OPT_RECONNECT  //my_bool *       如果发现连接丢失,启动或禁止与服务器的自动再连接。从MySQL 5.0.3开始,默认情况下禁止再连接,这是5.0.13中的新选项,提供了一种以显式方式设置再连接行为的方法

其他参数:https://blog.csdn.net/qq_38570571/article/details/79870946

连接

mycon是一个MySQL的连接指针,先初始化为NULL;接下来通过mysql_init分配或初始化一个适用于 mysql_real_connect() 的 MYSQL 对象。 如果参数是一个 NULL 指针,该函数分配、初始化并返回一个新对象。 否则,初始化对象并返回对象的地址。 如果 mysql_init() 分配了一个新对象,则在调用 mysql_close() 以关闭连接时将其释放。

c 复制代码
	mycon = mysql_real_connect(mycon,		//连接对象
                      "localhost",	//主机名或ip地址
                      "root",		//用户名
                      "123456",		//密码
                      "test",		//数据库名
                      3306,			//端口号
                      NULL,			//一般为NULL
                      0);			//通常为0, 设置为CLIENT_MULTI_QUERIES可以多行查询
    if(mycon == NULL)
    {
		printf("[error:%d]%s\n",mysql_errno(mycon),mysql_error(mycon));
        return -1;
    }

断开连接

c 复制代码
mysql_free_result(result);
mysql_close(mycon);

最后必须释放结果集,并管理mysql连接。

总结

c 复制代码
	//初始化
	MYSQL* mysql = mysql_init(NULL);
	if (!mysql)
	{
		printf("mysql_init failed\n");
		return NULL;
	}

	//设置超时时长
	int times = 1000;
	if (0 != mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, &times))
	{
		printf("mysql_options failed: %s\n", mysql_error(mysql));
		goto DONE;
	}

	//设置断开重新连接
	bool reconnect = true;
	if (0 != mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect))
	{
		printf("mysql_options failed: %s\n", mysql_error(mysql));
		goto DONE;
	}


	//连接
	MYSQL* connect = mysql_real_connect(mysql, "localhost", "root", "wy2892586", "test", 3306, NULL, CLIENT_MULTI_QUERIES);
	if (!connect)
	{
		printf("mysql_read_connect failed: %s\n", mysql_error(mysql));
		goto DONE;
	}

	//返回mysql连接
	return mysql;

DONE:
	//断开连接
	mysql_close(mysql);
	return NULL;

1.3 查询

mysql_real_connect() 尝试建立与在主机上运行的 MySQL 服务器的连接。 在执行任何其他需要有效 MYSQL 连接处理程序结构的 API 函数之前,客户端程序必须成功连接到服务器。

c 复制代码
	char query[]="SELECT * FROM emp";
	if(0 != mysql_query(mycon,query))
    {
        printf("[error:%d]%s\n",mysql_errno(mycon),mysql_error(mycon));
    }

连接成功之后,使用myql_query或mysql_real_query执行 SQL 语句。执行成功返回0,失败返回非零值。

通常,字符串必须由单个 SQL 语句组成,不带终止分号 ( ;) 或\g. 如果启用了多语句执行,则字符串可以包含多个用分号分隔的语句。

  • mysql_query()执行以 \0 结尾的 SQL 语句字符串,不能用于包含二进制数据的语句;
  • mysql_real_query()可以执行以非\0结尾的字符串(二进制数据可能包含\0字符)
  • mysql_store_result,结果集,但是不适合数据量特别大的时候
  • mysql_use_result,使用与数据集特别大的时候,逐行查询,用法和mysql_store_result一样
c 复制代码
MYSQL_RES* result = mysql_store_result(mycon);	//存储结果到客户端,
int row_num = mysql_num_rows(result);			//获取查询到的行数(只对SELECT语句有效)
int col_num = mysql_field_count(mycon);			//返回最近查询的列数(结果集中的列数)
//unsigned int mysql_num_fields(MYSQL_RES *result) //从结果集中获取查询到的字段数量

调用 mysql_real_query() 或 mysql_query() 后,必须为每个成功生成结果集的语句(SELECT、SHOW、DESCRIBE、EXPLAIN、CHECK TABLE 等)调用 mysql_store_result() 。 完成结果集后,还必须调用 mysql_free_result()。,执行成功 返回非0;

  • mysql_num_rows 获取查询到的数据行数(只对SELECT语句有效),如果是非查询语句可以使用**mysql_affected_rows**获取受影响的行数
  • **mysql_field_countmysql_num_fields**都可以获取查询到的列数,但是参数不一样
c 复制代码
if(row_num>0)
{
    MYSQL_ROW row;
    while(row = mysql_fetch_row(result))
    {
        for(int i =0;i<col_num;i++)
        {
            printf("%s ",row[i]);
        }
        printf("\n");
    }
}

**mysql_fetch_row()检索结果集的下一行,如果没有更多行要检索(抓完了)则返回NULL。**通过字段数量可以遍历到每一个字段值。

第二种方法

调用mysql_next_result

c 复制代码
do
{
	//3、获取数据集
	MYSQL_RES* mysql_res = mysql_store_result(mysql);
	if (!mysql_res)			//没有结果集,如use test;
	{
		// 如 use test ,没有数量
		uint64_t affected_rows = mysql_affected_rows(mysql);
		if (affected_rows == -1)
		{
			printf("mysql_store_result failed: %s\n", mysql_error(mysql));
			mysql_close(mysql);
			return;
		}
	}
	else
	{
		//4、获取每条数据
		int row_num = mysql_num_rows(mysql_res);
		if (row_num > 0)
		{
			MYSQL_ROW row = NULL;
			unsigned int cols = mysql_field_count(mysql);
			while (row = mysql_fetch_row(mysql_res))
			{
				for (int i = 0; i < cols; i++)
				{
					if (row[i])
					{
						printf("%s\t", row[i]);
					}
					else
					{
						printf("NULL\t");
					}
				}
				printf("\n");
			}
		}

		//释放结果集和关闭数据库
		mysql_free_result(mysql_res);
	}

} while (mysql_next_result(mysql) == 0);

1.4 获取字段信息

1.4.1 获取字段名

如果需要获取字段名,则需要在获取结果集之后获取。而且有多种获取字段名的方式。

c 复制代码
MYSQL_FIELD *field = NULL;
  • 方式一:从结果集中一个字段一个字段的抓取字段信息
c 复制代码
while (field = mysql_fetch_field(result))
{
    printf("%-15s", field->name);
}
  • 方式二:先把结果集中的所有字段都抓取到(返回存储所有字段的数组指针),然后通过字段总数去遍历数组
c 复制代码
field = mysql_fetch_fields(result);
for (int i = 0; i < col_num; i++)
{
    printf("%-15s", field[i].name);
}
  • 方式三:根据字段编号,从结果集中获取指定字段
cpp 复制代码
for (int i = 0; i < col_num; i++)
{
    field = mysql_fetch_field_direct(result, i);
    printf("%-15s", field->name);
}

1.4.2 获取字段/数据长度

所谓字段长度是指,字段能够存储数据的长度。所有数据都是以字符串的方式存储的,这个其实就是能够存储的字符串的长度。

类型 字节 长度 描述
SMALLINT 2 6 存储范围是[-32768,32767],加上符号总共六个字符,所有长度为6
VARCHAR(10) 4*10 40 不同的字符集可能不一样,总长度= 字符集规定的每个字符的字节数*指定的大小
c 复制代码
while (field = mysql_fetch_field(result))
{
    printf("%-15s", field->name,
           field->name_length
           field->length,
           field->max_length);
}
  • field->length为字段创建时指定的最大长度(如上表所示)
  • field->max_length为查询到该列数据中,最长的数据的长度
  • field->name_length为字段名的长度

如果想要获取每一行每个数据的长度,可以通过mysql_fetch_lengths函数来获取。

c 复制代码
MYSQL_ROW row;
//获取每一行记录
while (row = mysql_fetch_row(result))
{
    //获取每行记录的每个数据的长度
    unsigned long* lens = mysql_fetch_lengths(result);
    for (int i = 0; i < col_num; i++)
    {
        printf("%-15ld", lens[i]);
    }
	//获取每个数据
    for (int i = 0; i < col_num; i++)
    {
        printf("%-15s", row[i]);
    }
    printf("\n");
}

2.C API 参考

官网

3.总结(C使用)

不能多聚查询

sql 复制代码
//0、获取连接
MYSQL* mysql = GetMySQL();

//1、准备SQL语句
const char* use_sql = "use test;";
const char* query_sql = "select * from emp;";
//2、执行SQL
mysql_query(mysql, use_sql);
if (0 != mysql_query(mysql, query_sql))
{
	printf("mysql_query failed: %s\n", mysql_error(mysql));
	mysql_close(mysql);
	return;
}

//3、获取数据集,注意这种做法,不能一起执行
MYSQL_RES* mysql_res = mysql_store_result(mysql);
if (!mysql_res)
{
	printf("mysql_store_result failed: %s\n", mysql_error(mysql));
	mysql_close(mysql);
	return;
}

//4、获取每条数据
int row_num = mysql_num_rows(mysql_res);
if (row_num > 0)
{
	MYSQL_ROW row;
	unsigned int cols = mysql_field_count(mysql);

	while (row = mysql_fetch_row(mysql_res))
	{
		for (int i = 0; i < cols; i++)
		{
			if (row[i])
			{
				printf("%s\t", row[i]);
			}
			else
			{
				printf("NULL\t");
			}
		}
		printf("\n");
	}
}

//释放结果集和关闭数据库
mysql_free_result(mysql_res);

mysql_close(mysql);

不包含查询

sql 复制代码
//0、获取连接
MYSQL* mysql = GetMySQL();

//1、准备SQL语句
const char* query_sql = "use test; select * from emp;";
//2、执行SQL
if (0 != mysql_query(mysql, query_sql))
{
	printf("mysql_query failed: %s\n", mysql_error(mysql));
	mysql_close(mysql);
	return;
}

do
{
	//3、获取数据集
	MYSQL_RES* mysql_res = mysql_store_result(mysql);
	if (!mysql_res)			//没有结果集,如use test;
	{
		// 如 use test ,没有数量
		uint64_t affected_rows = mysql_affected_rows(mysql);
		if (affected_rows == -1)
		{
			printf("mysql_store_result failed: %s\n", mysql_error(mysql));
			mysql_close(mysql);
			return;
		}
	}
	else
	{
		//4、获取每条数据
		int row_num = mysql_num_rows(mysql_res);
		if (row_num > 0)
		{
			MYSQL_ROW row = NULL;
			unsigned int cols = mysql_field_count(mysql);
			while (row = mysql_fetch_row(mysql_res))
			{
				for (int i = 0; i < cols; i++)
				{
					if (row[i])
					{
						printf("%s\t", row[i]);
					}
					else
					{
						printf("NULL\t");
					}
				}
				printf("\n");
			}
		}

		//释放结果集和关闭数据库
		mysql_free_result(mysql_res);
	}

} while (mysql_next_result(mysql) == 0);

mysql_close(mysql);

包含字段查询

sql 复制代码
//获取连接
MYSQL* mysql = GetMySQL();

//准备SQL语句
const char* query_sql = "use test; select * from emp;";
//执行SQL
if (0 != mysql_query(mysql, query_sql))
{
	printf("mysql_query failed: %s\n", mysql_error(mysql));
	mysql_close(mysql);
	return;
}

do
{
	//获取数据集
	MYSQL_RES* mysql_res = mysql_store_result(mysql);
	if (!mysql_res)			//没有结果集,如use test;
	{
		// 如 use test ,没有数量
		uint64_t affected_rows = mysql_affected_rows(mysql);
		if (affected_rows == -1)
		{
			printf("mysql_store_result failed: %s\n", mysql_error(mysql));
			mysql_close(mysql);
			return;
		}
	}
	else
	{
		//获取字段名字
		unsigned int field_num = mysql_field_count(mysql);
		for (int i = 0; i < field_num; i++)
		{
			printf("%s\t", mysql_fetch_field_direct(mysql_res, i)->name);
		}
		printf("\n");

		//获取每条数据
		int row_num = mysql_num_rows(mysql_res);
		if (row_num > 0)
		{
			MYSQL_ROW row = NULL;
			unsigned int cols = mysql_field_count(mysql);
			while (row = mysql_fetch_row(mysql_res))
			{
				for (int i = 0; i < cols; i++)
				{
					if (row[i])
					{
						printf("%s\t", row[i]);
					}
					else
					{
						printf("NULL\t");
					}
				}
				printf("\n");
			}
		}

		//释放结果集和关闭数据库
		mysql_free_result(mysql_res);
	}

} while (mysql_next_result(mysql) == 0);

mysql_close(mysql);
相关推荐
JavaGuru_LiuYu10 小时前
Spring Boot 整合 SSE(Server-Sent Events)
java·spring boot·后端·sse
xuejianxinokok10 小时前
如何在 Rust 中以惯用方式使用全局变量
后端·rust
爬山算法10 小时前
Hibernate(26)什么是Hibernate的透明持久化?
java·后端·hibernate
彭于晏Yan10 小时前
Springboot实现数据脱敏
java·spring boot·后端
做cv的小昊10 小时前
【TJU】信息检索与分析课程笔记和练习(6)英文数据库检索—web of science
大数据·数据库·笔记·学习·全文检索
Darkershadow10 小时前
蓝牙学习之uuid与mac
python·学习·ble
alonewolf_9910 小时前
Spring IOC容器扩展点全景:深入探索与实践演练
java·后端·spring
super_lzb10 小时前
springboot打war包时将外部配置文件打入到war包内
java·spring boot·后端·maven
毛小茛10 小时前
芋道管理系统学习——项目结构
java·学习
warton8810 小时前
ubuntu24.04 安装mysql8.0.36
linux·运维·mysql