Database_API
Continuing from the database in the previous article, and then do some simple analysis on the functions of the database.
The reference link of this article:
MySQL C API usage (basic functions)
Mysql C API function detailed explanation
Common APIs of MySQL
When a commonly used program calls the MySQL database, it usually calls the following APIs, which will be analyzed one by one below.
-
mysql_init()
//函数原型 MYSQL *STDCALL mysql_init(MYSQL *mysql);
This
API
is mainly used to allocate or initialize anMySQL
object to connect to the MySQL server;
the return value isMYSQL *
;
the parameterMYSQL *mysql
is to specify anMYSQL
object. -
mysql_options()
//函数原型 int STDCALL mysql_options(MYSQL *mysql, enum mysql_option option, const void *arg);
This
API
can be used to set additional connection options and affect the behavior of the connection. This function can be called multiple times to set several options; the
parameterMYSQL *mysql
is to specify anMYSQL
object;
the parameterenum mysql_option option
is the connection option for the caller to choose to fill in;
the parameterconst void *arg
is combined with the previous parameter The value of the connection option to fill in.For filling in the connection options, you can refer to the mysql_options() function
-
mysql_real_connect()
//函数原型 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);
This
API
is mainly used to allocate or initialize anMySQL
object to connect toMySQL
the server.
The parameterMYSQL *mysql
is to specify anMYSQL
object, here ismysql_init
the pointer returned by the function;
the parameterconst char *host
specifies the host address;
the parameterconst char *user
specifiesmysql
the user name;
the parameterconst char *passwd
enters the password of the user name;
the parameterconst char *db
Specify the database, and link to the default database when the value is empty;
the parameterunsigned int port
specifies the port;
the parameterconst char *unix_socket
specifies the use of unix link mode, and when it is empty, it indicates that it is not applicablesocket
or the pipeline mechanism;
the parameterunsigned long clientflag
is usually set to 0. -
mysql_query()
//函数原型 int STDCALL mysql_query(MYSQL *mysql, const char *q);
This
API
is the most commonly used, and it is used in adding, deleting, checking, and modifying.query
It means query in English, but it means here执行
.
The parameterMYSQL *mysql
is to specify anMYSQL
object.
The parameterconst char *
enters aSQL
statement. -
mysql_store_result()
//函数原型 MYSQL_RES *STDCALL mysql_store_result(MYSQL *mysql);
Obtaining the result set is usually used with
mysql_query
thisAPI
to querySQL
the result returned by the previous statement.
The parameterMYSQL *mysql
is to specify anMYSQL
object
and the return valueMYSQL_RES
is a handle, which can be used tomysql_fetch_row
retrieve how many rows of data there are in the result set. -
mysql_use_result()
//函数原型 MYSQL_RES *STDCALL mysql_use_result(MYSQL *mysql);
This
API
is to use this function to obtain the result set after calling a command that can generate a result set; the
parameterMYSQL *mysql
is to specify anMYSQL
object. -
mysql_fetch_row()
//函数原型 MYSQL_ROW STDCALL mysql_fetch_row(MYSQL_RES *result);
Used in conjunction with
mysql_store_result
thisAPI
to get the content of each row.
The parameterMYSQL_RES *result
ismysql_use_result
the return value obtained through the get. -
mysql_free_result()
//函数原型 void STDCALL mysql_free_result(MYSQL_RES *result);
After operating the result set, be sure to call this function to release the memory;
the parameterMYSQL_RES *result
ismysql_use_result
the return value obtained through. -
mysql_error()
//函数原型 const char *STDCALL mysql_error(MYSQL *mysql);
The return value of the function is
const char*
the type, mainly to returnmysql
what error information occurred when the function was called recently.
The parameterMYSQL *mysql
is to specify anMYSQL
object -
mysql_close()
//函数原型 void STDCALL mysql_close(MYSQL *sock);
mysql_close()
Every program that calls the database connection must be called in the final stage.
Obviously, its function is to close the connection of a MySQL server.
The parameterMYSQL *mysql
is to specify anMYSQL
object
MySQL API application
Let's use a more practical example to API
write a simple stand-alone database management software.
Create two tables in the local database and store some initial information:
- First define the include file:
define.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <mysql.h>
#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <assert.h>
#pragma comment(lib,"libmysql.lib")
- Define a management class:
CManager
Provides the display of the main menu, the functions of connecting to the database and printing errors.
CManager.h
#pragma once
#include "define.h"
#include "CWorker.h"
#include "CAdmin.h"
class CManager
{
MYSQL m_sql;
CWorker m_work;
CAdmin m_admin;
int Menu();
bool ConnectDB();
public:
int Main();
static void PrintError(std::string sPromp)
{
auto & sql = getInstance().m_sql;
std::cout << sPromp << "(" << mysql_errno(&sql) << "):"
<< mysql_error(&sql) << std::endl;
system("pause");
}
static CManager& getInstance()
{
static CManager m;
return m;
}
CManager() : m_admin(m_sql),m_work(m_sql)
{
}
};
CManager.cpp
#include "CManager.h"
using namespace std;
int CManager::Menu()
{
system("cls");
const char* sPrior = m_admin.GetPrior() ? "普通" : "高级";
cout << "\n\n\t\t当前用户:" << m_admin.GetUser() << "【" << sPrior << "】" << endl;
puts("\t\t********************************");
puts("\t\t*\t1、浏览所有信息 *");
puts("\t\t*\t2、添加信息 *");
puts("\t\t*\t3、删除信息 *");
puts("\t\t*\t4、修改信息 *");
puts("\t\t*\t5、查找信息 *");
if (m_admin.GetPrior())
puts("\t\t*\t6、密码修改 *");
else
puts("\t\t*\t6、管理账号 *");
puts("\t\t*\t0、退出 *");
puts("\t\t********************************");
cout << "\t\t请选择:";
int i = 0;
cin >> i;
switch (i)
{
case 1:
m_work.Browse();
//m_work.Print();
break;
case 2:
m_work.Input();
break;
case 3:
m_work.Delete();
break;
case 4:
m_work.Modify();
break;
case 5:
m_work.Find();
break;
case 6:
m_admin.Main();
}
return i;
}
bool CManager::ConnectDB()
{
if (!mysql_init(&m_sql))
{
cout << "数据库初始化失败:" << mysql_error(&m_sql) << endl;
return false;
}
if (!mysql_real_connect(&m_sql, "localhost", "root", "123456", "worker", 3306, nullptr, 0))
{
cout << "连接数据库失败(" << mysql_errno(&m_sql) << "):" << mysql_error(&m_sql) << endl;
return false;
}
mysql_query(&m_sql, "set names \'GBK\'");
return true;
}
int CManager::Main()
{
if (!ConnectDB())
return -1;
if (!m_admin.Login())
return -1;
while (Menu())
;
return 0;
}
For the singleton mode of C++, please refer to Learning: Singleton mode in C++
- Define another account management class:
CAdmin
Functions mainly include account management options, account addition, deletion, modification and query operations.
CAdmin.h
#pragma once
#include "define.h"
class CAdmin
{
MYSQL &m_sql;
int m_nPrior{0};
std::string m_sName, m_sPass;
MYSQL_ROW FindName(const char* sName);
bool Check(const char* sName, const char* sPass);
void PrintRow(MYSQL_ROW row);
void Print()
{
Select("SELECT *FROM t_admin");
}
void InsertData(const std::string& sName, const std::string& sPass, int nPrior);
void DeleteData(const std::string& sName);
void Input();
void Delete();
void ChangePass();
void ChangePass(std::string sNew);
int Menu();
void Select(const char* sSQL);
public:
int Main();
bool Login();
CAdmin(MYSQL &sql) :m_sql(sql)
{
}
int GetPrior() const
{
return m_nPrior;
}
const char* GetUser() const
{
return m_sName.c_str();
}
};
CAdmin.cpp
#include "CAdmin.h"
#include "CManager.h"
using namespace std;
MYSQL_ROW CAdmin::FindName(const char* sName)
{
stringstream ss;
ss << "SELECT * FROM t_admin WHERE f_name = '" << sName <<"'";
int n = mysql_query(&m_sql, ss.str().c_str());
if (n)
{
CManager::PrintError("查找账号时发生错误"+ ss.str());
return nullptr;
}
auto res = mysql_store_result(&m_sql);
if (!res)
return nullptr;
return mysql_fetch_row(res);
}
bool CAdmin::Check(const char* sName, const char* sPass)
{
string sSQL = "SELECT* FROM t_admin WHERE f_name = '";
sSQL += sName;
sSQL += "' AND binary f_pass = '";
sSQL += sPass;
sSQL += "'";
int n = mysql_query(&m_sql, sSQL.c_str());
if (n)
{
cout << "登录失败,数据库查询错误:" << mysql_error(&m_sql);
return false;
}
auto res = mysql_store_result(&m_sql);
if (res && mysql_num_rows(res) > 0)
{
auto row = mysql_fetch_row(res);
m_sName =*row++;
m_sPass = *row++;
m_nPrior = atoi(*row);
return true;
}
cout << "你输入的账号或密码错误!" << endl;
return false;
}
void CAdmin::PrintRow(MYSQL_ROW row)
{
assert(row);
const char* str = *row++;
if (!str)
str = "无";
cout << str << '\t';
str = *row++;
if (!str)
str = "无";
cout << str << '\t';
str = *row++;
if (str)
str = atoi(str) ? "普通" : "高级";
else
str = "无";
cout <<str<< endl;
}
void CAdmin::Select(const char* sSQL)
{
int n = mysql_query(&m_sql, sSQL);
if (n)
{
CManager::PrintError("打印数据时发生错误:" + string(sSQL));
return;
}
auto res = mysql_store_result(&m_sql);
if (!res)
{
CManager::PrintError("打印数据时获取结果集错误:" + string(sSQL));
return;
}
system("cls");
const int ws[] = { 6,16,12,0 };
int i = -1;
cout <<"账号"<<'\t'<<"密码" <<'\t'<<"权限" << endl;
//puts("工号\t姓名\t工资\t入职日期");
MYSQL_ROW row;
int nCol = mysql_num_fields(res);
while (row = mysql_fetch_row(res))
PrintRow(row);
cout << "总共有 " << mysql_num_rows(res) << " 条记录" << endl;
system("pause");
}
void CAdmin::InsertData(const std::string& sName, const std::string& sPass, int nPrior)
{
char sSQL[256];
sprintf(sSQL, "INSERT INTO t_admin VALUES('%s','%s',%d)", sName.c_str(),
sPass.c_str(), nPrior);
if (mysql_query(&m_sql, sSQL))
CManager::PrintError("插入账号信息时出错");
else
Print();
}
void CAdmin::DeleteData(const std::string& sName)
{
stringstream ss;
ss << "DELETE FROM t_admin WHERE f_name='" << sName << "'";
if (mysql_query(&m_sql, ss.str().c_str()))
CManager::PrintError("删除账号信息时出错"+ss.str());
else
Print();
}
void CAdmin::Input()
{
string sName,sPass;
int nPrior;
cout << "请输入新的账号:";
cin >> sName;
auto row = FindName(sName.c_str());
if (row)
{
cout << "你输入的账号已存在:";
PrintRow(row);
system("pause");
return;
}
cout << "请输入密码和权限(0、高级 1、普通):";
cin >>sPass >> nPrior;
InsertData(sName, sPass, nPrior);
}
void CAdmin::Delete()
{
string sName, sPass;
int nPrior;
cout << "请输入要删除的账号:";
cin >> sName;
auto row = FindName(sName.c_str());
if (!row)
{
puts("你输入的账号不存在!");
system("pause");
return;
}
PrintRow(row);
printf("你确定要删除这条记录吗?[y/n]");
char c;
cin >> c;
DeleteData(sName);
}
void CAdmin::ChangePass()
{
string sOld, sNew, sConf;//confirm
cout << "请输入旧密码:";
cin >> sOld;
if (sOld != m_sPass)
{
cout << "你输入的旧密码不正确!"<<endl;
system("pause");
return;
}
cout << "请输入新密码:";
cin >> sNew;
cout << "请再次输入新密码:";
cin >> sConf;
if (sNew != sConf)
{
cout << "两次输入的新密码不一致!" << endl;
system("pause");
return;
}
if (sNew == m_sPass)
{
cout << "新密码和旧密码不能相同!" << endl;
system("pause");
return;
}
ChangePass(sNew);
}
void CAdmin::ChangePass(std::string sNew)
{
char sSQL[256];
sprintf(sSQL, "UPDATE t_admin SET f_pass='%s' WHERE f_name='%s'", sNew.c_str(),
m_sName.c_str());
int n = mysql_query(&m_sql, sSQL);
if (n)
{
CManager::PrintError("修改密码时出错!"+string(sSQL));
return;
}
size_t nRows = mysql_affected_rows(&m_sql);
if (nRows > 0)
{
m_sPass = sNew;
cout << "修改密码成功,总共更新了" << nRows << "条记录" << endl;
}
else
cout << "修改密码失败!" << endl;
system("pause");
}
int CAdmin::Menu()
{
system("cls");
puts("\t\t********************************");
puts("\t\t*\t1、浏览账号 *");
puts("\t\t*\t2、添加账号 *");
puts("\t\t*\t3、删除账号 *");
puts("\t\t*\t4、修改密码 *");
puts("\t\t*\t0、返回主菜单 *");
puts("\t\t********************************");
cout << "\t\t请选择:";
int n;
cin >> n;
switch (n)
{
case 1:
Print();
break;
case 2:
Input();
break;
case 3:
Delete();
break;
case 4:
ChangePass();
break;
}
return n;
}
int CAdmin::Main()
{
if (m_nPrior)
ChangePass();
else
while (Menu())
;
return 0;
}
bool CAdmin::Login()
{
string sName, sPass;
cout << "请输入账号和密码:" << endl;
cin >> sName >> sPass;
return Check(sName.c_str(), sPass.c_str());
}
- And define specific work classes:
CWorker
Addition, deletion, modification and query of operational data.
CWorker.h
#pragma once
#include "define.h"
#include "CSort.h"
#include "CFind.h"
class CWorker
{
MYSQL& m_sql;
CSort m_sort{this};
CFind m_find{this};
static void PrintField(MYSQL_ROW row, int nWidth);
static const int m_ws[] ;
void ModifyData(int nNumb);
void Print();
public:
static void PrintRow(MYSQL_ROW row, int nCol);
void Find()
{
while (m_find.Menu())
;
}
void Browse()
{
while (m_sort.Menu())
;
}
void Select(const char* sSQL);
MYSQL_ROW FindNumb(int nNumb);
bool DeleteNumb(int nNumb);
void Delete();
void Modify();
void Input();
CWorker(MYSQL& sql) :m_sql(sql)
{
}
};
CWorker.cpp
#include "CWorker.h"
#include "CManager.h"
using namespace std;
const int CWorker::m_ws[] = {6, 16, 12, 0};
//void CWorker::Print()
//{
// system("cls");
// int n = mysql_query(&m_sql,"SELECT * FROM t_people");
// if (n)
// {
// CManager::PrintError("打印数据时发生错误:");
// return;
// }
// auto res = mysql_store_result(&m_sql);
// if (!res)
// {
// CManager::PrintError("打印数据时获取结果集错误:");
// return;
// }
// puts("工号\t姓名\t工资\t入职日期");
// MYSQL_ROW row;
// int nCol = mysql_num_fields(res);
// while (row = mysql_fetch_row(res))
// {
// n = nCol;
// while (n--)
// {
// auto str = *row++;
// if (str)
// cout << str << "\t";
// else
// cout << "无\t";
// }
// putchar(10);
// }
// cout << "总共有 " << mysql_num_rows(res) << " 条记录" << endl;;
// system("pause");
//}
void CWorker::Print()
{
Select("SELECT *FROM t_people");
}
void CWorker::PrintField(MYSQL_ROW row, int nWidth)
{
auto str = *row;
cout << setiosflags(ios::left) << setw(nWidth);
if (str)
cout << str;
else
cout << "无";
}
void CWorker::PrintRow(MYSQL_ROW row, int nCol)
{
int i = -1;
while (++i < nCol)
PrintField(row++, m_ws[i]);
cout << endl;
}
MYSQL_ROW CWorker::FindNumb(int nNumb)
{
stringstream ss;
ss << "SELECT * FROM t_people WHERE f_numb = " << nNumb;
int n = mysql_query(&m_sql,ss.str().c_str());
if (n)
{
CManager::PrintError("查找工号时发生错误");
return nullptr;
}
auto res = mysql_store_result(&m_sql);
if (!res)
return nullptr;
return mysql_fetch_row(res);
}
bool CWorker::DeleteNumb(int nNumb)
{
stringstream ss;
ss << "DELETE FROM t_people WHERE f_numb = " << nNumb;
int n = mysql_query(&m_sql, ss.str().c_str());
if (n)
{
CManager::PrintError("删除工号时发生错误");
return false;
}
return true;
}
void CWorker::Delete()
{//size_t n = mysql_affected_rows(&m_sql);
int nNumb;
cout << "请输入要删除的工号:";
cin >> nNumb;
auto row = FindNumb(nNumb);
if (!row)
{
puts("你输入的工号不存在!");
system("pause");
return;
}
PrintRow(row, _countof(m_ws));
printf("你确定要删除这条记录吗?[y/n]");
char c = 0;
cin >> c;//不出现类似于getchar 失效问题
if (c == 'Y' || c == 'y')
{
if(DeleteNumb(nNumb))
Print();
}
}
void CWorker::ModifyData(int nNumb)
{//size_t n = mysql_affected_rows(&m_sql);
string sName, sDate;
float fSala;
cout << "请输入姓名和工资、入职日期:";
cin >> sName >> fSala >> sDate;
char sSQL[256];
sprintf(sSQL, "UPDATE t_people SET f_name='%s',f_sala=%g,f_date='%s'"
" WHERE f_numb=%d", sName.c_str(),fSala, sDate.c_str(), nNumb);
if (mysql_query(&m_sql, sSQL))
CManager::PrintError("插入员工信息时出错");
else
Print();
}
void CWorker::Select(const char* sSQL)
{
int n = mysql_query(&m_sql, sSQL);
if (n)
{
CManager::PrintError("打印数据时发生错误:"+string(sSQL));
return;
}
auto res = mysql_store_result(&m_sql);
if (!res)
{
CManager::PrintError("打印数据时获取结果集错误:" + string(sSQL));
return;
}
system("cls");
const int ws[] = { 6,16,12,0 };
int i = -1;
cout << setiosflags(ios::left) << setw(ws[0]) << "工号" << setw(ws[1])
<< "姓名" << setw(ws[2]) << "工资" << "入职日期" << endl;
//puts("工号\t姓名\t工资\t入职日期");
MYSQL_ROW row;
int nCol = mysql_num_fields(res);
while (row = mysql_fetch_row(res))
PrintRow(row++, nCol);
cout << "总共有 " << mysql_num_rows(res) << " 条记录" << endl;
system("pause");
}
void CWorker::Modify()
{
int nNumb;
cout << "请输入要修改的工号:";
cin >> nNumb;
auto row = FindNumb(nNumb);
if (!row)
{
puts("你输入的工号不存在!");
system("pause");
return;
}
PrintRow(row, _countof(m_ws));
printf("你确定要修改这条记录吗?[y/n]");
char c = 0;
cin >> c;//不出现类似于getchar 失效问题
if (c == 'Y' || c == 'y')
ModifyData(nNumb);
}
void CWorker::Input()
{
int nNumb;
cout << "请输入工号:";
cin >> nNumb;
auto row = FindNumb(nNumb);
if (row)
{
cout << "你输入的工号已存在:";
PrintRow(row, _countof(m_ws));
system("pause");
return;
}
string sName,sDate;
float fSala;
cout << "请输入姓名和工资、入职日期:";
cin >> sName >> fSala>>sDate;
//stringstream ss;//sprintf
char sSQL[256];
sprintf(sSQL,"INSERT INTO t_people VALUES(%d,'%s',%g,'%s')", nNumb, sName.c_str(),
fSala, sDate.c_str());
if (mysql_query(&m_sql, sSQL))
CManager::PrintError("插入员工信息时出错");
else
Print();
//size_t n = mysql_affected_rows(&m_sql);
}
- Find class:
CFind
Which fields to search for.
CFind.h
#pragma once
#include "define.h"
class CWorker;
class CFind
{
CWorker* m_pWorker;
void FindByNumb();
void FindByName();
void FindBySalary();
void FindByDate();
public:
int Menu();
CFind(CWorker* pWorker) :m_pWorker(pWorker)
{
}
};
CFind.cpp
#include "CFind.h"
#include "CWorker.h"
using namespace std;
void CFind::FindByNumb()
{
int nNumb;
printf("请输入要查找的工号:");
cin >> nNumb;
auto row = m_pWorker->FindNumb(nNumb);
if (row)
m_pWorker->PrintRow(row,4);
else
puts("你输入工号不存在!");
system("pause");
}
void CFind::FindByName()
{
string sName;//C++字符串
int nCount = 0;
cout << "请输入要查找的姓名(模糊查找):";
cin >> sName;
stringstream ss;
ss << "SELECT *FROM t_people WHERE f_name LIKE '%%" << sName << "%%'";
m_pWorker->Select(ss.str().c_str());
}
void CFind::FindBySalary()
{
float fMin, fMax;
printf("请输入要查的工资段(2个数字):");
cin >> fMin >> fMax;
char sSQL[256];
sprintf(sSQL, "SELECT * FROM t_people WHERE f_sala>=%g AND f_sala<=%g", fMin, fMax);
m_pWorker->Select(sSQL);
}
void CFind::FindByDate()
{
string sMin, sMax;
printf("请输入要查的日期段(yyyy-mm-dd yyyy-mm-dd):");
cin >> sMin >> sMax;
char sSQL[256];
sprintf(sSQL, "SELECT * FROM t_people WHERE f_date>='%s' AND f_date<='%s'",
sMin.c_str(), sMax.c_str());
m_pWorker->Select(sSQL);
}
int CFind::Menu()
{
system("cls");
puts("\n\n\t\t********************************");
puts("\t\t*\t1、按工号查找 *");
puts("\t\t*\t2、按姓名查找 *");
puts("\t\t*\t3、按工资段查找 *");
puts("\t\t*\t4、按日期段查找 *");
puts("\t\t*\t0、返回主查找 *");
puts("\t\t********************************");
printf("\t\t请选择:");
int n;
scanf_s("%d", &n);
switch (n)
{
case 1:
FindByNumb();
break;
case 2:
FindByName();
break;
case 3:
FindBySalary();
break;
case 4:
FindByDate();
break;
}
return n;
}
- sort class:
CSort
CSort.h
#pragma once
class CWorker;
class CSort
{
CWorker* m_pWorker;
public:
int Menu();
CSort(CWorker* pWorker) :m_pWorker(pWorker)
{
}
};
CSort.cpp
#include "define.h"
#include "CSort.h"
#include "CWorker.h"
using namespace std;
int CSort::Menu()
{
system("cls");
//golang
puts("\n\n\t\t********************************");
puts("\t\t*\t1、按工号排序 *");
puts("\t\t*\t2、按姓名排序 *");
puts("\t\t*\t3、按工资排序 *");
puts("\t\t*\t4、按日期排序 *");
puts("\t\t*\t0、返回主菜单 *");
puts("\t\t********************************");
cout <<"\t\t请选择:";
int n;
cin >> n;
if (n > 0 && n < 5)
{
string ss[] = { "f_numb","f_name","f_sala","f_date"};
string sSQL = "SELECT * FROM t_people ORDER BY ";
sSQL += ss[n - 1];
m_pWorker->Select(sSQL.c_str());
}
return n;
}
Summarize
The above program is mainly the process of designing ideas, and the MYSQL
commonly used ones are called through the program API
to deepen MYSQL API
the understanding.