MySQL数据库访问
前提准备
要访问MySQL需要下载MySQL,下载时会一起下载MySQL客服端和服务端以及依赖。以C++/C访问MySQL需要用到MySQL提供的API接口,这些API可以在MySQL官网上找到。
yum install myaql-community-server
MySQL句柄
MYSQL* mysql=mysql_init(nullptr);
连接函数
MYSQL *mysql_real_connect(
MYSQL *mysql, // MySQL 连接句柄
const char *host, // 主机名或IP地址
const char *user, // MySQL用户名
const char *passwd, // 密码
const char *db, // 默认数据库
unsigned int port, // 端口号
const char *unix_socket,// Unix域套接字路径
unsigned long client_flag // 客户端标志
);
#include <iostream>
#include <mysql/mysql.h>
#define HOST "localhost" //或#define HOST "120.0.0.1"
#define USER "root"
#define PASSWORD "123456"
#define DB "conn"
#define PORT 3306
main()
{//......mysql = mysql_real_connect(mysql,HOST,USER,PASSWORD,DB,PORT,nullptr,0);if(mysql==nullptr){std::cout<<"mysql_real_connect fail"<<std::endl;return 1;}//......return 0;
}
参数解释
mysql:mysql句柄,由mysql_init()初始化的连接句柄指针
host:主机名(如‘localhost’或‘127.0.0.1’)
user:用户名如果为null,表示当前系统登录用户名
passwd:用户密码,如果为null,表示不使用密码
db:要使用的数据库名称,可以为null
port:mysql服务的端口号,为0就是默认端口3306
unix_socker:套接字路径,设置为null,表示默认套接字
client_flag:标志位,很少用到,设置为0
user为null解释
假设你住在一个小区(MySQL服务器),单元楼有门禁(MySQL的权限系统)。
方式1:用专属门禁卡(显式指定用户名)
你从钱包里掏出写有 "业主A" 的门禁卡(
user="业主A"
),刷卡进门。结果:
如果卡有效(用户存在且密码正确)→ 门开。
如果卡无效(用户不存在)→ 被保安拦下。
方式2:刷脸(
user=NULL
,用系统用户名)
你没带门禁卡,直接走到摄像头前刷脸。
系统自动识别你的脸,查出你是 "住户B"(当前系统登录用户名),然后尝试用这个身份开门。
结果:
如果小区登记过你的脸(MySQL有用户
住户B
)且无需密码 → 门开。如果没登记或需要密码但你没输入 → 保安拒绝进入。
所以user=null就像刷脸一样,方便但是不安全。
句柄的意义
句柄可以避免直接操作底层,借书的人不会去图书馆仓库找书,句柄隐藏了MySQL内部的复杂实现,如果借书不换,图书馆的书就会越来越少,所以申请的句柄,用完后就需要释放句柄。
1. 办借书证 →
mysql_init()
和mysql_real_connect()
你需要先到前台 办一张借书证(类似创建句柄
MYSQL* conn
)。图书管理员(MySQL服务器)会登记你的信息(用户名、密码),然后给你一个 借书证编号(句柄的值)。
→ 这个编号不是书本身,而是你借书的权限凭证。
2. 查目录 →
mysql_query()
你用借书证去查图书目录(SQL查询),比如找“所有编程书”(
SELECT * FROM books
)。管理员给你一份临时书单(结果集句柄
MYSQL_RES* res
),上面列出了书的位置和名字。3. 取书 →
mysql_fetch_row()
你根据书单去书架拿书(获取数据行)。每本书的内容(数据)是具体的,但书单(结果集)只是一个指向书的指针。
每次拿一本(
mysql_fetch_row
),直到书架空了(返回NULL
)。4. 还书 →
mysql_free_result()
和mysql_close()
读完书后,你要把书单归还(释放结果集),否则管理员会以为你还在用。
最后退还借书证(关闭连接),否则图书馆会一直保留你的借阅名额(资源泄漏)。
设置客服端字符集
用vscode连接MySQL,这两者的编码方式可能不同,就需要以MySQL的编码方式为准,把vscode的编码同步。
mysql_set_character_set(mysql,"utf8");
选择数据库
刚开始的连接就包含了库的设置,后面出现选择数据库就可以调用这个函数。
mysql_select_db(mysql,"conn");
执行sql语句
mysql是申请的句柄,char的内容会变为字符串输入到mysql中,成功放回0,否则放回非零。
int mysql_query(MYSQL*, const char*)
示例
std::string insert1 = "insert into stu values(null,'张三',18,187562354)";
n = mysql_query(mysql, insert1.c_str());
if (n != 0)
{std::cout << "mysql_query fail" << std::endl;return 1;
}
获取查询结构
在上面的代码中,char内容是select的话,是不会显示表的信息,select不像其它语句增删改,查的信息会保存在一个地方,需要使用API去获取信息。
MYSQL_RES* mysql_store_result(MYSQL*)
函数的返回值为MYSQL_RES* 类型,是一个结构体指针类型,保存了查询结构和相关属性,如下图,每一个char* 都指向表的一个内容,所以要查看表的内容,就需要遍历所有元素,打印出内容。
示例
MYSQL_RES *res = mysql_store_result(mysql);
if (res == nullptr)
{
std::cout << "mysql_store_result fail" << std::endl;
return 1;
}
获取行的个数
int row = mysql_num_rows(res);
获取列的个数
int col = mysql_num_fields(res);
遍历打印
MYSQL_ROW mysql_fetch_row(MYSQL_RES*)
这个函数没调用一次会自动+1,遍历第一行再次调用就到下一行了。
for (int i = 0; i < row; i++)
{
MYSQL_ROW r = mysql_fetch_row(res);
for (int j = 0; j < col; j++)
{
std::cout << r[j] << '/t';
}
std::cout << std::endl;
}
释放申请的资源
void mysql_free_result(MYSQL_RES*)
释放结果集
void mysql_close(MYSQL*);
释放句柄
总代码
#include <iostream>
#include <mysql/mysql.h>
#define HOST "localhost" // 或#define HOST "120.0.0.1"
#define USER "root"
#define PASSWORD "XyK@71986582"
#define DB "conn"
#define PORT 3306
int main()
{// 创建MySQL句柄MYSQL *mysql = mysql_init(nullptr);// 连接数据库mysql = mysql_real_connect(mysql, HOST, USER, PASSWORD, DB, PORT, nullptr, 0);if (mysql == nullptr){std::cout << "mysql_real_connect fail" << std::endl;return 1;}// 设置客户端字符集,与mysqld保持一致。int n = mysql_set_character_set(mysql, "utf8");if (n != 0){std::cout << "mysql_setcharacter_set fail" << std::endl;return 1;}// 选择要操作的数据库// 在做连接时已经选好了现在就不用选,只是考虑到中途需要换其他库的情况。// n = mysql_select_db(mysql,"conn");// 准备工作做好了,接下来操作库:// 执行SQL语句std::string insert1 = "insert into stu values(null,'张三',18,187562354)";std::string insert2 = "insert into stu values(null,'李四',18,187562154)";std::string delete1 = "delete from stu where id=1";std::string update = "update stu set name='王五' where name = '李四'";std::string sel = "select * from stu";n = mysql_query(mysql, sel.c_str());if (n != 0){std::cout << "mysql_query fail" << std::endl;return 1;}MYSQL_RES *res = mysql_store_result(mysql);if (res == nullptr){std::cout << "mysql_store_result fail" << std::endl;return 1;}int row = mysql_num_rows(res);int col = mysql_num_fields(res);for (int i = 0; i < row; i++){MYSQL_ROW r = mysql_fetch_row(res);for (int j = 0; j < col; j++){std::cout << r[j] << '\t';}std::cout << std::endl;}mysql_free_result(res);mysql_close(mysql);return 0;
}