前言
我们之前一直都是在用命令行来操作数据库,今天我们换一种方式来操作,用编程语言!
其实,还可以考虑用 图形化GUI页面 来操作,肯定可以的,不过这个我自己也没怎么玩过,可能以后会吧,上网搜索了一下,好像 MySQL Workbench(免费)、Navicat(收费) 这两个还不错,就交由大家自行去掌握了!
一、环境配置
其实我不太想把配置环境的过程放上来,因为我认为这是不得不品的一环,必须让大家都来尝一口(
可以先来回顾下这篇文章
Linux软硬链接和动静态库(20)
界面应该都是大差不差的,我这里呈现的是我现在这个时间如何下载所需的库文件
首先,进入MySQL官网,选择DOWNLOADS
再点击这个 MySQL Community (GPL) Downloads »
再点击这个 Connector/C++
再选择适合自己的系统版本直接下载就行了,这个时候你就拿到了包
之后就是熟悉的利用 rz -E 把刚刚下载的库文件上传到云服务器,使用 tar 命令将压缩包解压到当前目录下,然后再熟悉的软链接一下,makefile搞一下
但是今天我想介绍另外一种方法,使用命令行很方便的一种方式
# 下载库文件
sudo apt-get install libmysqlclient-dev
sudo apt-get install libmysqlcppconn-dev
# 查看头文件路径
dpkg -L libmysqlclient-dev
直接一键下好,原理由DS大人给出如下:
二、一些API的体验
创建MySQL对象
在连接数据库之前,需要先创建一个MySQL对象,创建MySQL对象的函数如下:
MYSQL* mysql_init(MYSQL *mysql);
- 该函数用来分配或者初始化一个 MySQL 对象,用于连接 MySQL 服务器。
- 如果传入的参数是 nullptr ,那么 mysql_init 将自动为你分配一个 MySQL 对象并返回。
- 如果传入的参数是一个地址,那么 mysql_init 将在该地址处帮你完成初始化。
MYSQL 对象中包含了各种信息,其类型定义如下
typedef struct 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 *charset;
MYSQL_FIELD *fields;
struct MEM_ROOT *field_alloc;
uint64_t affected_rows;
uint64_t insert_id; /* id if insert on table with NEXTNR */
uint64_t 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;
enum enum_resultset_metadata resultset_metadata;
bool free_me; /* If free in mysql_close */
bool reconnect; /* set to 1 if automatic reconnect */
/* session-wide random string */
char scramble[SCRAMBLE_LENGTH + 1];
LIST *stmts; /* list of all statements */
const struct 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.
*/
bool *unbuffered_fetch_owner;
void *extension;
} MYSQL;
- MYSQL对象中的 methods 变量是一个结构体变量,该变量里面保存着很多函数指针,这些函数指针将会在数据库连接成功以后的各种数据操作中被调用。
连接数据库
创建完 MySQL 对象后就可以连接数据库了,连接数据库的函数如下
MYSQL *STDCALL mysql_real_connect(MYSQL *mysql, const char *host,
const char *user, const char *passwd,
const char *db, unsigned int port,
const char *unix_socket,
unsigned long clientflag);
参数说明:
- mysql: 表示在连接数据库前,调用 mysql_init 函数创建的 MySQL 对象。
- host: 表示需要连接的 MySQL 服务器的IP地址, “127.0.0.1” 表示连接本地 MySQL 服务器。
- user: 表示连接 MySQL 服务器时,所使用用户的用户名。
- passwd: 表示连接 MySQL 服务器时,所使用用户的密码
- db: 表示连接 MySQL 服务器后,需要使用的数据库。
- port: 表示连接的 MySQL 服务器,所对应的端口号。
- unix_socket: 表示连接时应该使用的套接字或命名管道,通常设置为 NULL 。
- clientflag: 可以设置为多个标志位的组合,表示允许特定的功能,通常设置为0。
返回值说明:
- 如果连接数据库成功,则返回一个 MySQL 对象,该对象与第一个参数的值相同。
- 如果连接数据库失败,则返回 NULL 。
关闭数据库连接
与数据库交互完毕后,需要关闭数据库连接,关闭数据库连接的函数如下
void mysql_close(MYSQL *sock);
- 该函数的参数,就是连接数据库前调用 mysql_init 创建的 MySQL 对象。
- 如果传入的 MySQL 对象是 mysql_init 自动创建的,那么调用 mysql_close 时就会释放这个对象。
下发SQL请求
与数据库建立连接期间,就可以向 MySQL 服务器下发 SQL 请求,下发 SQL 请求的函数如下:
int mysql_query(MYSQL *mysql, const char *q);
参数说明:
- mysql: 表示在连接数据库前,调用 mysql_init 函数创建的 MySQL 对象。
- q: 表示向MySQL服务器下发的 SQL 请求,SQL 最后可以不带分号。
返回值说明:
- 返回值为0表示 SQL 执行成功,否则表示 SQL 执行失败。
统一编码格式
在连接数据库之后,需要统一客户端和服务器的编码格式,避免在数据交互过程中出现乱码,设置编码格式的函数如下
int mysql_set_character_set(MYSQL *mysql, const char *csname);
参数说明:
- mysql: 表示在连接数据库前,调用 mysql_init 函数创建的 MySQL 对象。
- csname: 表示要设置的编码格式,如 " utf8 " 。
返回值说明:
- 返回值为0表示设置成功,否则表示设置失败。
获取查询结果
获取查询结果的函数如下:
MYSQL_RES* mysql_store_result(MYSQL *mysql);
- 该函数会调用指定 MySQL 对象中对应的函数指针来获取查询结果,并将获取到的查询结果保存到 MYSQL_RES 变量中进行返回。
- 需要注意的是,MYSQL_RES 变量的内存空间是 malloc 出来的,因此在使用完后需要调用 free 函数进行释放,否则会造成内存泄露。
typedef struct MYSQL_RES {
uint64_t row_count;
MYSQL_FIELD *fields;
struct MYSQL_DATA *data;
MYSQL_ROWS *data_cursor;
unsigned long *lengths; /* column lengths of current row */
MYSQL *handle; /* for unbuffered reads */
const struct MYSQL_METHODS *methods;
MYSQL_ROW row; /* If unbuffered read */
MYSQL_ROW current_row; /* buffer to current row */
struct MEM_ROOT *field_alloc;
unsigned int field_count, current_field;
bool eof; /* Used by mysql_fetch_row */
/* mysql_stmt_close() had to cancel this result */
bool unbuffered_fetch_cancelled;
enum enum_resultset_metadata metadata;
void *extension;
} MYSQL_RES;
获取查询结果的行数的函数如下:
my_ulonglong mysql_num_rows(MYSQL_RES *res);
获取查询结果的列数的函数如下:
unsigned int mysql_num_fields(MYSQL_RES *res);
获取查询结果中的一行数据的函数如下:
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
获取查询结果的列属性的函数如下:
MYSQL_FIELD* mysql_fetch_fields(MYSQL_RES *res);
实际示例
我们现在来一个实际例子,你就明白了,我现在在 Xshell 里面登录一个账户 connector 并且使用数据库 connector 再查询表 user
接着我在 Vscode 里面写了以下代码
#include <iostream>
#include <string>
#include <mysql/mysql.h>
const std::string host = "127.0.0.1";
const std::string user = "connector";
const std::string passwd = "@Lhq123456";
const std::string db = "conn";
const unsigned int port = 3306;
int main()
{
// std::cout << "mysql client version : " << mysql_get_client_info() << std::endl;
MYSQL* my = mysql_init(nullptr);
if (my == nullptr)
{
std::cerr << "init MySQL error" << std::endl;
return 1;
}
if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
{
std::cerr << "connect MySQL error" << std::endl;
return 2;
}
mysql_set_character_set(my, "utf8");
std::string sql = "select * from user";
int n = mysql_query(my, sql.c_str());
if (n == 0) std::cout << sql << " success " << std::endl;
else
{
std::cout << sql << " failed " << std::endl;
return 3;
}
MYSQL_RES* res = mysql_store_result(my);
if (res == nullptr)
{
std::cerr << "mysql_store_result error" << std::endl;
return 4;
}
// "这个res有点像句柄"
my_ulonglong rows = mysql_num_rows(res);
my_ulonglong fields = mysql_num_fields(res);
std::cout << "行: " << rows << std::endl;
std::cout << "列: " << fields << std::endl;
// 属性
MYSQL_FIELD* fields_array = mysql_fetch_fields(res);
for (my_ulonglong i = 0 ; i < fields ; i++)
{
std::cout << fields_array[i].name << "\t";
}
std::cout << std::endl;
// 内容
for (my_ulonglong i = 0 ; i < rows ; i++)
{
MYSQL_ROW row = mysql_fetch_row(res);
for (my_ulonglong j = 0 ; j < fields ; j++)
{
std::cout << row[j] << "\t";
}
std::cout << std::endl;
}
// std::string sql;
// while (true)
// {
// std::cout << "MySQL >>> ";
// if (!std::getline(std::cin, sql) || sql == "quit")
// {
// std::cout << "bye bye" << std::endl;
// break;
// }
// int n = mysql_query(my, sql.c_str());
// if (n == 0)
// {
// std::cout << sql << " success: " << n << std::endl;
// }
// else
// {
// std::cerr << sql << " failed: " << n << std::endl;
// }
// }
// std::cout << "connect success" << std::endl;
mysql_free_result(res);
mysql_close(my);
return 0;
}
接着 make 编译以下,运行 ./mytest,理所应当的查询结果如下:
总结
至此差不多 MySQL 的学习就告一段终了~
但是感概要学的还有好多啊,什么 Docker、Redis、Qt,甚至前端我也想学一学,项目也想做,下一步该学些什么呢,害,走一步是一步吧,先脚踏实地的干着再说~
想了一下,还是先把 Linux网络部分 先学完吧,其实我是那一块被干碎了心塞中途跳车学了下 MySQL 缓冲一下,这下又要开始痛苦网络了,哎,我们未来再见!