
作者 Eaton
导语
在后台开发中,我们经常需要和数据库打交道,而在 C++ 开发中,MySQL Connector/C++ 只提供了基础操作接口,复杂的业务常常需要一系列复杂的调用过程,非常容易出错,那有什么方法可以避免呢?TarsCpp 中提供了数据库操作类 TC_Mysql,使我们能够方便地进行数据库操作,提高业务开发效率。本文将对 TC_Mysql 进行介绍分析。
目录
MySQL
简介
数据库是计算机应用系统中一种专门管理数据资源的系统,以数据为中心,解决了传统文件存储数据存在的数据冗余、移植性差等问题。在后台开发中,数据库操作具有非常重要的地位,不可避免地需要和数据库打交道。现在市面上的数据库软件多种多样,最常用的便是 MySQL。它是一款安全、跨平台、高效的关系型数据库系统,由瑞典的 MySQL AB 公司开发、发布并支持。由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,使得很多公司都采用 MySQL 数据库以降低成本。

数据库的基础操作包括增、删、改、查四种操作,对应的在 MySQL 中为 Insert, Delete, Update, Select 等,能够方便地实现对数据库中数据的管理。
MySQL 常用 API
MySQL 支持了各种主流的程序设计语言,提供了丰富的数据库操作 API 函数。在 C++ 开发中,MySQL 官方提供了相关的数据库连接动态库 MySQL Connector/C++,接口定义在 mysql.h 中,包含 MySQL 基础操作 API,像常用的 mysql_real_connect, mysql_real_query, mysql_store_result, mysql_fetch_row 等。其中
mysql_real_connect用于创建到 MySQL 数据库服务的连接;mysql_real_query用于执行 MySQL 语句;mysql_store_result用于将执行结果保存到本地;mysql_fetch_row用于获取返回结果中的行。
这四个函数一般情况下能够满足大部分需求,它们在 mysql.h 中的声明如下
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);
int STDCALL mysql_real_query(MYSQL *mysql, const char *q, unsigned long length);
MYSQL_RES *STDCALL mysql_store_result(MYSQL *mysql);
MYSQL_ROW STDCALL mysql_fetch_row(MYSQL_RES *result);
mysql_real_connect 函数有很多参数,涵盖了连接数据库所需要的基本信息如 host, user, password 等,成功创建连接会获得一个 MYSQL 对象,并将参数中的 MYSQL * 指针 mysql 指向该对象,供其它操作使用。
mysql_real_query 函数需要传入刚才提到的连接对象指针,SQL 字符串 q 和字符串长度 length,返回执行结果的行数。
mysql_store_result 函数传入 MYSQL 对象指针,返回执行结果,类型为 MYSQL_RES。
mysql_fetch_row 传入获取的结果,返回每行的数据。
存在的问题
然而使用这些接口进行一次 MySQL 操作是非常麻烦的一件事,下面我们通过一个例子来看看如何通过这四个函数实现一次 MySQL 查询操作
#include "mysql.h"
using namespace std;
int main()
{
// 创建 MYSQL 对象
MYSQL *mysql = mysql_init(NULL);
// 创建连接
mysql_real_connect(mysql, "127.0.0.1", "root", "123456", "db_tars", 3306, NULL, 0);
// 执行sql语句
string sql = "select * from server";
mysql_real_query(mysql, sql.c_str(), sql.length());
// 获取执行结果
MYSQL_RES *res = mysql_store_result(mysql);
// 字段名数组
vector<string> fields;
MYSQL_FIELD *field;
// 通过 mysql_fetch_field 获取字段名保存在数组 fields 中
while((field = mysql_fetch_field(res)))
{
fields.push_back(field->name);
}
// 声明 row 用于保存每行数据
MYSQL_ROW row;
// 读取返回结果所有字段值
// mysql_fetch_row 从 res 中获取一行数据
while((row = mysql_fetch_row(res) != (MYSQL_ROW)NULL))
{
// 获取每个字段值的字符串长度,因为每个字段是一个字符数组 (C 风格字符串)
unsigned long * lengths = mysql_fetch_lengths(res);
for(size_t i = 0; i < fields.size(); i++)
{
cout << fields[i] << ":" << string(row[i], lengths[i]) << ";";
}
cout << endl;
}
return 0;
}
上述代码在 main 函数中,用最简单的方式实现了查询操作,没有包含任何错误和返回值判断的逻辑,但是看起来已经很复杂了。而实际业务场景中通常还需要对一些错误码还有返回结果进行判断,比如连接失败或断开,返回值为空等,总的来说,存在以下几个问题
- 需要自己构造 SQL 语句,容易出错;
- 需要开发者自己添加错误码和异常的判断和处理逻辑;
- 每次查询返回的结果需要调用
mysql_fetch系列的多个函数才能完成结果读取。
可见,开发者需要关注的细节太多,会很大程度上降低了开发效率。因此,把开发者无需关注的或重复的过程和细节隐藏起来,将 MySQL 操作 API 进一步封装,显得非常必要。自己封装的话未免太

TarsCpp提供了一个名为TC_Mysql的类,封装了MySQL操作,简化了数据库交互,包括数据库配置接口TC_DBConf,数据存储类MysqlRecord和MysqlData,以及异常类TC_Mysql_Exception。TC_Mysql提供了Insert、Update、Replace、Delete和Query等便捷函数,避免手动构造SQL,提高开发效率。
最低0.47元/天 解锁文章
652





