# C MySQL API 详解
# 普通调用
# 开发环境
需要引用头文件
#include <mysql.h>
- 默认已经安装了 MySQL 环境
- 配置 VS2022 项目属性
- 右键项目,进入属性
- 需要在
属性
的 VC++ 目录中包含目录和引用目录中分别添加 MySQL 安装文件夹下的 include 文件夹和 lib 文件夹 - 在属性中输入目录下的附加依赖项添加 MySQL 加密动态库
# 代码测试
#include <stdio.h> | |
#include <mysql.h> | |
int main(void) | |
{ | |
printf("MySQL Environment Successful\n"); | |
return 0; | |
} | |
// 引用头文件不报错,即环境匹配成功 |
# MySql.h
用法
# 运行流程图
# C 连接 MySQL 语法详解
一共
两
个部分,一个通过一个小程序实例,通过注释的形式将 MySQL API 吃透,另一种是分解版逐步吃透。其为MySQL.h内部头文件
# 合集版
# 本地数据先进行的操作
show databases; | |
create database cpp; | |
use cpp; | |
show TABLES; | |
-- 创建 dept 部门表 | |
CREATE TABLE dept ( | |
d_id INT PRIMARY KEY, | |
d_name VARCHAR ( 20 ), | |
d_des VARCHAR ( 50 ) | |
); | |
SHOW TABLES; | |
DESC dept; | |
INSERT INTO dept VALUES(01,'陆军','河南'); | |
INSERT INTO dept VALUES(02,'第二陆军','开封'); | |
INSERT INTO dept VALUES(03,'第三陆军','西安'); | |
INSERT INTO dept VALUES(04,'第四陆军','山东'); | |
INSERT INTO dept VALUES(05,'第五陆军','菏泽'); | |
INSERT INTO dept VALUES(06,'第六陆军','商丘'); | |
INSERT INTO dept VALUES(07,'第七陆军','郑州'); | |
INSERT INTO dept VALUES(08,'第八陆军','洛阳'); | |
SELECT * FROM dept; |
# C 调用合集
#include <stdio.h> | |
#include <mysql.h> | |
int main(void) | |
{ | |
printf("MySQL Environment Successful\n"); | |
// 初始化运行环境 | |
// 该函数将分配初始化,并返回新对象,并通过返回这个对象去连接 MySQL 服务器 | |
MYSQL* mysql = mysql_init(NULL); | |
// 判断是否初始化成功 | |
if (mysql == NULL) | |
{ | |
printf("mysql_init() error"); | |
return -1; | |
} | |
printf("数据库初始化成功\n"); | |
// 连接 MySQL 服务器 | |
mysql = mysql_real_connect | |
( | |
mysql, //mysql_init () 函数返回值 | |
"localhost", //mysql 的 IP 地址 | |
"root", //myslq 的用户名 | |
"5211314", //mysql 的密码 | |
"cpp", // 使用的数据库名称 | |
3306, // 监听端口,0 为默认 3306 端口 | |
NULL, // 本地套接字,不指定为 NULL | |
0 // 默认 0 | |
); | |
// 检查数据库连接情况 | |
if (mysql == NULL) | |
{ | |
printf("mysql_real_connect() error\n"); | |
return -1; | |
} | |
printf("数据库连接成功\n"); | |
// 输出 MySQL API 使用的编码,参数为数据库对象 | |
printf("mysql api使用的默认编码:%s\n", mysql_character_set_name(mysql)); | |
// 设置数据库编码为 utf8, | |
// 参数:数据库对象,编码 | |
mysql_set_character_set(mysql, "gbk"); // 将编码改为 gbk 才可以进行数据插入,报错,乱码 | |
printf("mysql api修改后的编码为:%s\n", mysql_character_set_name(mysql)); | |
// 执行 sql 语句 | |
// 查询 cpp 数据库下的 dept 部门表 | |
const char* sql = "select * from dept"; | |
// 执行 sql 语句 | |
// 参数:数据库对象,const char * 的数据库执行语句 | |
// 执行成功返回 0 | |
int ret = mysql_query(mysql, sql); | |
if (ret != 0) | |
{ | |
//mysql_error 返回 mysql 数据库对象错误描述 | |
printf("mysql_query()失败了,原因:%s\n", mysql_error(mysql)); | |
return -1; | |
} | |
// 取出结果,参数 mysql 数据对象 | |
//MYSQL_RES 对应一块内存八寸执行之后的结果集 | |
// 若错误,返回 NULL | |
MYSQL_RES* res = mysql_store_result(mysql); | |
if (res == NULL) | |
{ | |
printf("mysql_store_result()失败了,原因是:%s\n", mysql_error(mysql)); | |
return -1; | |
} | |
// 得到结果集中的列数 | |
// 参数:传入 mysql_store_result () 得到的返回值 | |
int num = mysql_num_fields(res); | |
// 得到所有列的名字,并且输出 | |
// 参数传入 mysql_store_result () 得到的返回值 | |
//MYSQL_FIELD 对应的是一个结构体 | |
MYSQL_FIELD* fields = mysql_fetch_fields(res); | |
// 遍历输出 mysql 的 name | |
for (int i = 0; i < num; i++) | |
{ | |
printf("%s\t\t", fields[i].name); | |
} | |
printf("\n"); | |
// 遍历结果集中的所有行 | |
// 参数:mysql_store_result () 得到的返回值 | |
// 成功得到当前记录中每一个字段的值 | |
// 失败 / 数据读完 返回 NULL | |
MYSQL_ROW row; | |
while ((row = mysql_fetch_row(res)) != NULL) | |
{ | |
// 将当前列中的每一列信息读出 | |
for (int i = 0; i < num; ++i) | |
{ | |
printf("%s\t\t", row[i]); | |
} | |
printf("\n"); | |
} | |
// 释放资源 - 结果集 | |
mysql_free_result(res); | |
// 写入数据 | |
//MySQL 默认自动提交数据库 | |
// 设置事务为手动提交 | |
mysql_autocommit(mysql, 0); | |
// 执行成功返回 0 | |
int ret1 = mysql_query(mysql, "insert into dept values(10,'第一海军','海南')"); | |
int ret2 = mysql_query(mysql, "insert into dept values(11,'第二海军','福建')"); | |
int ret3 = mysql_query(mysql, "insert into dept values(12,'第三海军','辽宁')"); | |
printf("ret1=%d ret2 = %d ret3 = %d\n", ret1, ret2, ret3); | |
if (ret1 == 0 && ret2 == 0 && ret3 == 0) | |
{ | |
printf("执行成功,正在提交事务\n"); | |
// 提交事务 | |
mysql_commit(mysql); | |
} | |
else | |
{ | |
printf("执行失败,正在回滚....\n"); | |
printf("执行失败原因: %s\n", mysql_error(mysql)); | |
mysql_rollback(mysql); | |
} | |
// 释放数据库资源 | |
mysql_close(mysql); | |
return 0; | |
} |
# 分解头文件
# 初始化运行环境
// 该函数将分配初始化,并返回新对象,并通过返回这个对象去连接 MySQL 服务器,得到一块内存并保存 | |
MYSQL* mysql_init(MYSQL * mysql); | |
// 参数 NULL |
# 连接数据库
MYSQL * mysql_real_connect( | |
MYSQL *mysql, //mysql_init () 函数的返回值即指向的指针 | |
const char *host, // 主机地址 ip 地址,localhost,NULL 代表本地连接 | |
const char *user, // 服务器用户名 | |
const char *passwd,// 连接服务器密码 | |
const char *db, // 要使用数据库名称 | |
unsigned int port, // 监听的端口号,若为 0,则默认 mysql 的 3306 端口 | |
const char *unix_socket, // 本地套接字,不指定为 NULL | |
unsigned long clientflag // 通常指定为 0 | |
); |
# 执行 SQL 语句
int mysql_query(MYSQL *mysql,const char *query); |
参数:
- mysql:mysql_real_connect () 的返回值
- query : 可以执行的 sql 语句,不要
;
返回值: - 成功返回
0
就,结果集在 MySQL 对象中 - 错误返回
非0
# 获取结果集
- 将结果集从 MySQL (参数) 对象中取出
- MYSQL_RES 对应一块内存,保存着查询之后的结果集
- 返回具有多个结果的 MYSQL_RES 结果集合
- 若错误,返回 NULL
MYSQL_RES *mysql_store_result(MYSQL *mysql); |
# 获取结果集的列数
unsigned int mysql_num_fields(MYSQL_RES *result); |
参数
- 调用 mysql_store_result () 得到的返回值
返回值 - 结果集中的列数
# 获取结果集中所有列的名字
MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *result); |
参数
- mysql_store_result () 得到的结果集
返回值 MYSQL_FIELD*
指向的一个结构体
# 结构体定义
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; |
# 获得结果集中字段的长度
unsigned long *mysql_fetch_lengths(MYSQL_RES *result); |
参数:
- result: 通过查询得到的结果集
返回值
- 无符号长整数的数组表示各列的大小,若错误返回 NULL
# 遍历结果集
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
参数:
result:通过查询得到的结果集
返回值:成功:得到了当前记录中每个字段的值
失败 / 数据已经读完:NULL,
# MYSQL_ROW
typedef char** MYSQL_ROW;
- 返回值二级指针,
char**
指向一个指针数组,类型是数组,里面的元素仍未指针,char*
类型, char* []
:数组中的字符串对应的一列数据- 如果想要遍历整个结果集,需要对函数 MYSQL_ROW 进行循环调用
# 资源回收
// 释放结果集 | |
void mysql_free_result(MYSQL_RES *result); | |
// 关闭 MySQL 实例 | |
void mysql_close(MYSQL *mysql); |
# 字符编码
# 返回当前编码
// 获取API默认使用的字符编码(当前连接返回默认的字符集)
const char * mysql_character_set_name(MYSQL *mysql);
# 设置编码
// 设置 API 使用的字符集 | |
int mysql_set_character_set(MYSQL *mysql,char *csname); |
参数:
- csname 为要设置的字符集:常用
utf8
# 事务
MySql 会默认进行事务提交,需要设置逻辑处理时,多吃写操作,开始时创建事务,结束时判断是否全部成功,再提交或处理错误
my_bool mysql_autocommit(MYSQL *mysql,my_bool mode);
参数:
mode
如果模式为1
,启用
autocommit 模式- 如果模式为
0
,禁止
autocommit 模式
# 事务提交
my_bool mysql_commit(MYSQL *mysql);
返回值:
- 成功:0
- 失败:非 0
# 数据回滚
回滚到事务处理前的状态
my_bool mysql_rollback(MYSQL *mysql); |
返回值:
- 成功: 0
- 失败: 非 0
# 打印错误信息
// 返回错误的描述 | |
const char *mysql_error(MYSQL *mysql); | |
// 返回错误的编码 | |
unsigned int mysql_error(MYSQL *mysql); |
# 参数传递依赖关系
# C++ 封装 MySQL API
# 什么时候调用释放结果集
- 析构函数
- 可能会对数据库进行多次查询,每次查询一次都会得到结果集,查询是清空掉上次的结果集
# 源代码
# MySQLConnect.h
#pragma once | |
#ifndef MYSQLCONNECT_H | |
#define MYSQLCONNECT_H | |
#include <iostream> | |
#include <mysql.h> | |
using namespace std; | |
class MySqlConnect | |
{ | |
private: | |
// 什么时候调用释放结果集 | |
//1, 析构函数 2,可能会对数据库进行多次查询,每次查询一次都会得到结果集,查询是清空掉上次的结果集 | |
void freeResult(); // 释放结果集 | |
MYSQL* m_conn = nullptr; // 保存 MySQL 初始化的私有成员 | |
MYSQL_RES* m_result = nullptr; // 报错结果集 | |
MYSQL_ROW m_row = nullptr; // 保存着当前字段的所有列的数值 | |
public: | |
// 初始化数据库连接 | |
MySqlConnect(); | |
// 释放数据库连接 | |
~MySqlConnect(); | |
// 连接数据库,使用默认端口可省略端口书写 | |
bool connect(string user, string passwd,string dbName,string ip,unsigned short port = 3306 ); | |
// 更新数据库 (插入,更新,删除),传递字符串 | |
bool update(string sql); | |
// 查询数据库,单词 query: 查询 | |
bool query(string sql); | |
// 遍历查询得到的结果集,每调一次,从结果集中取出一条数据 | |
bool next(); | |
// 得到结果集中的字段值,取记录里面字段方法 | |
string value(int index); | |
// 事务操作,关闭自动提交 | |
bool transaction(); | |
// 提交事务 | |
bool commit(); | |
// 事务回滚; | |
bool rollback(); | |
}; | |
#endif // !MYSQLCONNECT_H |
# MySQLConnect.cpp
#include "MySQLConnect.h" | |
void MySqlConnect::freeResult() | |
{ | |
if (m_result) | |
{ | |
mysql_free_result(m_result); | |
m_result = nullptr; | |
} | |
} | |
MySqlConnect::MySqlConnect() | |
{ | |
m_conn = mysql_init(nullptr); | |
mysql_set_character_set(m_conn, "utf8"); | |
} | |
MySqlConnect::~MySqlConnect() | |
{ | |
if (m_conn != nullptr) | |
{ | |
mysql_close(m_conn); | |
} | |
freeResult(); | |
} | |
bool MySqlConnect::connect(string user, string passwd, string dbName, string ip, unsigned short port) | |
{ | |
//ip 传入为 string,使用.str 将 ip 转为 char * 类型 | |
MYSQL* ptr = mysql_real_connect(m_conn, ip.c_str(), user.c_str(), passwd.c_str(), dbName.c_str(), port, nullptr, 0); | |
// 连接成功返回 true | |
// 如果连接成功返回 TRUE,失败返回 FALSE | |
return ptr!=nullptr; | |
} | |
bool MySqlConnect::update(string sql) | |
{ | |
//query 执行成功返回 0 | |
if (mysql_query(m_conn, sql.c_str())) | |
{ | |
return false; | |
}; | |
return true; | |
} | |
bool | |
MySqlConnect::query(string sql) | |
{ | |
freeResult(); | |
//query 执行成功返回 0 | |
if (mysql_query(m_conn, sql.c_str())) | |
{ | |
return false; | |
}; | |
m_result = mysql_store_result(m_conn); | |
return true; | |
} | |
bool MySqlConnect::next() | |
{ | |
// 如果结果集为空则没有必要遍历 | |
if (m_result != nullptr) | |
{ | |
// 保存着当前字段的所有列的数值 | |
m_row = mysql_fetch_row(m_result); | |
return true; | |
} | |
return false; | |
} | |
string MySqlConnect::value(int index) | |
{ | |
// 表示列的数量 | |
int row_num = mysql_num_fields(m_result); // 函数得到结果集中的列数 | |
// 如果查询的的 index 列大于总列,或小于 0,是错误的 | |
if (index >= row_num || index < 0) | |
{ | |
return string(); | |
} | |
char* val = m_row[index]; // 若为二进制数据,中间是有 "\0" 的 | |
unsigned long length = mysql_fetch_lengths(m_result)[index]; | |
return string(val,length); // 传入 length 就不会以 "\0" 为结束符,而是通过长度把对应的字符转换为 string 类型 | |
} | |
bool MySqlConnect::transaction() | |
{ | |
return mysql_autocommit(m_conn,false); // 函数返回值本身就是 bool 类型 | |
} | |
bool MySqlConnect::commit() | |
{ | |
return mysql_commit(m_conn);// 提交 | |
} | |
bool MySqlConnect::rollback() | |
{ | |
return mysql_rollback(m_conn);//bool 类型,函数成功返回 TRUE,失败返回 FALSE | |
} |