C++ 通过API MySQL操作
VS2019连接MySQL数据库
通过API进行数据库操作,VS链接的步骤见链接中的文章
VS 2019 链接MySQL数据库
MySQL 操作简介
MySQL的相关操作的操作详见下文(这兄弟的这篇文章总结的不错)
半个月时间把MySQL重新巩固了一遍,梳理了一篇几万字 “超硬核” 文章!
C++中mysql.h文件中函数及数据简介
- 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;
//host为主机名一般为localhost
//user为用户名默认为root
//passwd为数据的密码默认为123456
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; //端口号默认为3036,可在数据库安装目录下的配置文件中找到
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_FIELD 简介
typedef struct MYSQL_FIELD {
char *name; /* 字段名或者成为列名 */
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;
使用MYSQL_FIELD主要用于数据库查询时用于输出字段名将查询的表格输出,在程序中常常定义MYSQL_FIELD*类型来存储一个表格中一个字段的信息,获取所有字段的信息需要用调用函数逐个获得。
- MYSQL_ROWS和MYSQL_DATA 简介
typedef struct MYSQL_ROWS {
struct MYSQL_ROWS *next; //用于指向下一行MYSQL_ROWS类型,形成链表
MYSQL_ROW data;
unsigned long length;
} MYSQL_ROWS;
typedef struct MYSQL_DATA {
MYSQL_ROWS *data;
struct MEM_ROOT *alloc;
uint64_t rows;
unsigned int fields;
} MYSQL_DATA;
typedef char **MYSQL_ROW; /* return data as array of strings */
MYSQL_ROWS表示查询到的一行的相关数据通过链表存储,MYSQL_ROW为char**类型,将每一行的信息存储在二维字符数组中。
- MYSQL_RES 查询结果集
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;
函数汇总
- 初始化数据库
MYSQL *mysql_init(MYSQL* mysql)
分配或者初始化MYSQL类型的结构体为数据库连接做准备,如果mysql时null 该函数将分配并初始化,通过指针返回初始化的地址。如果内存不足返回null.
- 连接数据库
MYSQL *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 client_flag)
通过该函数实现与数据库的连接第一个参数为经过mysql_init()的一个MYSQL类型的地址,host为主机名,与本地主机连接默认为localhost,user为登录数据库的用户名,默认为root,passwd为登录密码,默认为12345,db为数据库名称,port为连接的端口号,可在数据库安装目录的配置文件查询一般为3036,unix_socket描述了使用的套接字或命名管道,一般设置为NULL,client_falg通常设置为0.
- 数据查询,增加,删除,修改的执行函数mysql_query
int STDCALL mysql_query(MYSQL *mysql, const char *q);
参数:MYSQL* ,将连接数据库的MYSQL类型的指针传入,const char* q,为数据库查询语句等,例如"select * from table名"。
返回类型为int 型,其中1表示查询失败,0表示查询到结果,具体的查询结果可用其他函数查看。STDCALL为_stdcall的宏定义,代表了函数调用时参数的从右到左的入栈顺序。
- 使用mysql_store_result获取查询结果
MYSQL_RES* mysql_store_result(MYSQL* mysql)
该函数通过MYSQL与MYSQL_RES的关联将查询结果返回,返回类型为MAYSQL_RES指针类型,MYSQL_RES的简介见上文,其中查询的结果包括行数,列数,以及字段名等,查询结果按照行以链表的方式存储。
MYSQL_FIELD *STDCALL mysql_fetch_field(MYSQL_RES *result);
函数的功能为获取查询结果集中的字段的相关数据,例如字段名等,返回类型为MYSQL_FIELD*,其具体内容在上文已经给出,常常通过这个函数的返回结果输出字段紧接着输出查询的信息。
MYSQL_ROW STDCALL mysql_fetch_row(MYSQL_RES *result
函数的参数为MYSQL_RES*,返回类型为MYSQL_ROW,该类型包含查询到的一行信息,MYSQL为char**类型。详细关系见上文的mysql.h的文件简介。
- 释放内存并关闭连接
void STDCALL mysql_free_result(MYSQL_RES *result)
void STDCALL mysql_close(MYSQL *sock);
这两个函数分别释放结果集的内存,和关闭连接,虽然在个人电脑上运行程序不做最后一步不会带来很大的问题但是在其他场合缺少却可能引发灾难性的后果。
提示: 进行每次查询后释放MYSQL_RES *指针指向的内存,否则编译通过也可能出现 Commands out of sync;的错误,
运行实例
下面是将操作封装为类,可以随时使用
#pragma once
#include<string>
#include<winsock.h>
#include<mysql.h>
#include<Windows.h>
using std::string;
class DataBaseProcessing
{
private:
MYSQL mysql; //MySQL连接
MYSQL_RES* res; //一个查询结果集
MYSQL_ROW row; //表示数据行
const char* username ="**"; //数据库用户名
const static int port=**; //数据库端口
const char* pwd="***"; //数据库密码
const char* host="localhost";
const char* databaseName="***";
public:
bool ConnectDatabase();
void FreeConnect();
// 数据库查询操作
MYSQL_RES* DatabaseQuery(const char* statement);
// 修改数据库表
bool DatabaseModify(const char* statement);
};
#include "DataBaseProcessing.h"
#include<string>
bool DataBaseProcessing::ConnectDatabase()
{
//初始化mysql对象
mysql_init(&mysql);
if (!mysql_real_connect(&mysql, host, username, pwd, databaseName, port, NULL,0))
{
MessageBoxA(NULL, "数据库连接失败!", "警告", MB_OK);
return false;
}
else {
return true;
}
}
void DataBaseProcessing::FreeConnect()
{
mysql_free_result(res);
mysql_close(&mysql);
}
// 数据库查询操作
MYSQL_RES* DataBaseProcessing::DatabaseQuery(const char* st)
{
if (mysql_real_query(&mysql, st,unsigned int(strlen(st))))
{
string str = string(mysql_error(&mysql));
if (!str.empty())
{
char* ctr = new char[str.size() + 1];
strcpy_s(ctr, str.size() + 1, str.c_str());
}
return nullptr;
}
if (!(res = mysql_store_result(&mysql)))
{
return nullptr;
}
else {
return res;
}
return nullptr;
}
// 修改数据库表
bool DataBaseProcessing::DatabaseModify(const char* st)
{
mysql_query(&mysql, "set names gbk");
if (mysql_real_query(&mysql,st,unsigned int(strlen(st))))
{
string str = string(mysql_error(&mysql));
if (!str.empty())
{
char* ctr = new char[str.size() + 1];
strcpy_s(ctr, str.size() + 1, str.c_str());
}
return false;
}
else {
return true;
}
}
以上代码仅仅是封装好的类,并不能直接运行,还需要自己编写相关的主函数等其他部分。