用C++封装MySQL的API的教程_MySQL
其实相信每个和mysql打过交道的程序员都应该会尝试去封装一套mysql的接口,这一次的封装已经记不清是我第几次了,但是每一次我希望都能做的比上次更好,更容易使用。
先来说一下这次的封装,遵守了几个原则,其中部分思想是从python借鉴过来的:
1.简单
简单,意味着不为了微小的效率提升,而去把接口搞的复杂。因为本身数据库存储效率的瓶颈并不是那一两次内存copy,代码中随处可以看到以这个为依据的设计。
2.低学习成本
使用一套新库通常意味着投入学习成本,而这次的封装并没有像django那样实现一套完整的模型系统,也没有做soci那样的语法分析器,我选择最简单易懂的方式:做sql语句拼接器,所以对习惯了使用原生mysql api的朋友,学习成本很低
3.模块化
代码实际包括了两个模块,一个是mysql client端的封装,一个是sql的拼接器,这两个模块是完全独立的,调用者可以任意组合或者独立使用。
4.尽量使用STL以及模板,简化代码编写
最大的特点就是大量使用了stringstream进行类型转化,减少了大量的重复代码。
OK,基于以上的简单介绍,我们先来看一下
一.mysql client端的封装:
class CMYSQLWrapper { /** * @brief 获取错误信息 * * @return 错误信息 */ char* GetErrMsg(); /** * @brief 连接MYSQL,已经支持了自动重连模式,即mysql server关闭链接会自动重连 * * @param ip IP * @param user 用户名 * @param pwd 密码(没有则传NULL) * @param db 库(没有则传NULL) * * @return 0 succ * else fail */ int Open(const char* ip,const char* user,const char* pwd,const char* strDb); /** * @brief 关闭链接并释放result */ void Close(); /** * @brief 执行SQL语句 * * @param strSql 执行语句 * @param result 执行结果 * * @return 0 succ * else fail */ int Query(const char* strSql); /** * @brief 针对Read(select)相关的的Query,可以支持blob了 * * @param strSql sql语句 * @param vecData rows * * @return 0 succ * else fail */ int Query(const char* strSql, vector<map<string, MYSQLValue> > &vecData); /** * @brief 针对Write(insert,update,delete)相关的Query * * @param strSql sql语句 * @param affectRowsCount 影响的行的个数 * * @return 0 succ * else fail */ int Query(const char* strSql, int& affectRowsCount); /** * @brief Select时获取数据,记得手工析构,或者用StMYSQLRes * * @param result 执行结果 * * @return 0 succ * else fail */ int Result(MYSQL_RES *&result); /** * @brief 返回影响行数 * * @return >0 succ * 0 没有更新 * <0 fail */ int AffectedRows(); /** * @brief 主要是将blob转成字符串 * * @param src blob源 * @param len 长度 * * @return 转化后的字符串 */ string EscStr(const char* src,uint32_t len); /** * @brief 将字符串中的某些字符转化(如') * * @param src 字符串 * * @return 转化后的字符串 */ string EscStr(const char* src); }; class CMYSQLWrapper { /** * @brief 获取错误信息 * * @return 错误信息 */ char* GetErrMsg(); /** * @brief 连接MYSQL,已经支持了自动重连模式,即mysql server关闭链接会自动重连 * * @param ip IP * @param user 用户名 * @param pwd 密码(没有则传NULL) * @param db 库(没有则传NULL) * * @return 0 succ * else fail */ int Open(const char* ip,const char* user,const char* pwd,const char* strDb); /** * @brief 关闭链接并释放result */ void Close(); /** * @brief 执行SQL语句 * * @param strSql 执行语句 * @param result 执行结果 * * @return 0 succ * else fail */ int Query(const char* strSql); /** * @brief 针对Read(select)相关的的Query,可以支持blob了 * * @param strSql sql语句 * @param vecData rows * * @return 0 succ * else fail */ int Query(const char* strSql, vector<map<string, MYSQLValue> > &vecData); /** * @brief 针对Write(insert,update,delete)相关的Query * * @param strSql sql语句 * @param affectRowsCount 影响的行的个数 * * @return 0 succ * else fail */ int Query(const char* strSql, int& affectRowsCount); /** * @brief Select时获取数据,记得手工析构,或者用StMYSQLRes * * @param result 执行结果 * * @return 0 succ * else fail */ int Result(MYSQL_RES *&result); /** * @brief 返回影响行数 * * @return >0 succ * 0 没有更新 * <0 fail */ int AffectedRows(); /** * @brief 主要是将blob转成字符串 * * @param src blob源 * @param len 长度 * * @return 转化后的字符串 */ string EscStr(const char* src,uint32_t len); /** * @brief 将字符串中的某些字符转化(如') * * @param src 字符串 * * @return 转化后的字符串 */ string EscStr(const char* src); };
代码中的注释已经描述的很清楚了,语言描述不清楚,我们直接来看一下gtest的代码:
select: string g_name = "good"; int g_sex = 1; string g_name_up = "update"; int g_sex_up = 2; TEST(mysql_wrapper_easy, select) { vector<map<string,MYSQLValue> > vecData; string sql = "select * from tb_test where name = '"+g_name_up+"'"; int ret = g_client.Query(sql.c_str(),vecData); ASSERT_EQ(ret, 0) << g_client.GetErrMsg(); foreach(vecData, it_vec) { foreach(*it_vec, it_map) { cout << it_map->first << ","; if (it_map->first == "sex") { cout << it_map->second.as<uint32_t>(); } else { cout << it_map->second.data(); } cout << "," << it_map->second.size() << endl; } } } int main(int argc, char **argv) { int ret = g_client.Open("localhost","dantezhu",NULL,"soci"); //int ret = g_client.Open("127.0.0.1","dantezhu",NULL,"soci"); if (ret) { cout << ret << "," << g_client.GetErrMsg() << endl; return -1; } ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } string g_name = "good"; int g_sex = 1; string g_name_up = "update"; int g_sex_up = 2; TEST(mysql_wrapper_easy, select) { vector<map<string,MYSQLValue> > vecData; string sql = "select * from tb_test where name = '"+g_name_up+"'"; int ret = g_client.Query(sql.c_str(),vecData); ASSERT_EQ(ret, 0) << g_client.GetErrMsg(); foreach(vecData, it_vec) { foreach(*it_vec, it_map) { cout << it_map->first << ","; if (it_map->first == "sex") { cout << it_map->second.as<uint32_t>(); } else { cout << it_map->second.data(); } cout << "," << it_map->second.size() << endl; } } } int main(int argc, char **argv) { int ret = g_client.Open("localhost","dantezhu",NULL,"soci"); //int ret = g_client.Open("127.0.0.1","dantezhu",NULL,"soci"); if (ret) { cout << ret << "," << g_client.GetErrMsg() << endl; return -1; } ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } insert: TEST(mysql_wrapper_easy, insert) { clear_data(); stringstream ss; ss << "insert into tb_test(name,sex) values('" << g_client.EscStr(g_name.c_str()) << "'," << g_sex << ");"; int affectRowsNum; int ret = g_client.Query(ss.str().c_str(), affectRowsNum); ASSERT_EQ(ret, 0) << g_client.GetErrMsg(); EXPECT_GE(affectRowsNum,0) << g_client.GetErrMsg(); } TEST(mysql_wrapper_easy, insert) { clear_data(); stringstream ss; ss << "insert into tb_test(name,sex) values('" << g_client.EscStr(g_name.c_str()) << "'," << g_sex << ");"; int affectRowsNum; int ret = g_client.Query(ss.str().c_str(), affectRowsNum); ASSERT_EQ(ret, 0) << g_client.GetErrMsg(); EXPECT_GE(affectRowsNum,0) << g_client.GetErrMsg(); }
可以看出,对于mysql的收发包已经很简洁了,但是sql语句的拼装却显得十分臃肿。所以这个时候sql语句拼装器-SQLJoin闪亮登场!
二.sql语句拼装器-SQLJoin
class SQLJoin { public: /** * @brief 用流处理的方式,添加一个列名 * * @param key 列名 * * @return 0 */ SQLJoin& operator << (const string& key); /** * @brief 用流处理的方式,添加一个SQLPair对象 * * @param pair_data SQLPair对象 * * @return 0 */ SQLJoin& operator << (const SQLPair& pair_data); /** * @brief 输出所有列名(如name, sex, age) * * @return 所有列名 */ string keys(); /** * @brief 输出所有列值(如'dante', 1, 25) * * @return 所有列值 */ string values(); /** * @brief 输入所有列名-列值,并用指定分隔符分割(如name='dante', sex=1, age=25) * * @param split_str 分割符,默认是用',',也可以用and、or之类 * * @return 所有列名-列值 */ string pairs(const string& split_str = ","); /** * @brief 清空所有数据 */ void clear(); }; class SQLJoin { public: /** * @brief 用流处理的方式,添加一个列名 * * @param key 列名 * * @return 0 */ SQLJoin& operator << (const string& key); /** * @brief 用流处理的方式,添加一个SQLPair对象 * * @param pair_data SQLPair对象 * * @return 0 */ SQLJoin& operator << (const SQLPair& pair_data); /** * @brief 输出所有列名(如name, sex, age) * * @return 所有列名 */ string keys(); /** * @brief 输出所有列值(如'dante', 1, 25) * * @return 所有列值 */ string values(); /** * @brief 输入所有列名-列值,并用指定分隔符分割(如name='dante', sex=1, age=25) * * @param split_str 分割符,默认是用',',也可以用and、or之类 * * @return 所有列名-列值 */ string pairs(const string& split_str = ","); /** * @brief 清空所有数据 */ void clear(); };
看看我们用了SQLJoin之后的代码应该如何:
TEST(mysql_wrapper_join, insert) { clear_data(); SQLJoin sql_join; sql_join << SQLPair("name", g_client.EscapeRealString(g_name.c_str())) << SQLPair("sex", g_sex); stringstream ss; ss << "insert into tb_test(" << sql_join.keys() << ") values(" << sql_join.values() << ")"; int affectRowsNum; int ret = g_client.ExecuteWrite(ss.str().c_str(), affectRowsNum); ASSERT_EQ(ret, 0) << g_client.GetErrMsg(); EXPECT_GE(affectRowsNum,0) << g_client.GetErrMsg(); } TEST(mysql_wrapper_join, update) { SQLJoin sql_join; sql_join << SQLPair("name", g_name_up) << SQLPair("sex", g_sex_up); stringstream ss; ss << "update tb_test set " << sql_join.pairs() << " where name='" << g_name <<"';"; int affectRowsNum; int ret = g_client.ExecuteWrite(ss.str().c_str(),affectRowsNum); ASSERT_EQ(ret, 0) << g_client.GetErrMsg(); EXPECT_GE(affectRowsNum,0) << g_client.GetErrMsg(); } TEST(mysql_wrapper_join, insert) { clear_data(); SQLJoin sql_join; sql_join << SQLPair("name", g_client.EscapeRealString(g_name.c_str())) << SQLPair("sex", g_sex); stringstream ss; ss << "insert into tb_test(" << sql_join.keys() << ") values(" << sql_join.values() << ")"; int affectRowsNum; int ret = g_client.ExecuteWrite(ss.str().c_str(), affectRowsNum); ASSERT_EQ(ret, 0) << g_client.GetErrMsg(); EXPECT_GE(affectRowsNum,0) << g_client.GetErrMsg(); } TEST(mysql_wrapper_join, update) { SQLJoin sql_join; sql_join << SQLPair("name", g_name_up) << SQLPair("sex", g_sex_up); stringstream ss; ss << "update tb_test set " << sql_join.pairs() << " where name='" << g_name <<"';"; int affectRowsNum; int ret = g_client.ExecuteWrite(ss.str().c_str(),affectRowsNum); ASSERT_EQ(ret, 0) << g_client.GetErrMsg(); EXPECT_GE(affectRowsNum,0) << g_client.GetErrMsg(); }
从上面的代码可以看出,代码的可维护性和健壮性得到了很大的提升。
OK,简单的介绍就是这样,说的比较简略,大家有兴趣可以直接看代码,也欢迎给我提意见和建议。代码下载路径如下:
mysql_wrapper
明天这份代码就会作为数据库访问层正式进入生产环境的代码中,因此有什么bug我也会及时在这里更新。

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

MySQL convient aux débutants car il est simple à installer, puissant et facile à gérer les données. 1. Installation et configuration simples, adaptées à une variété de systèmes d'exploitation. 2. Prise en charge des opérations de base telles que la création de bases de données et de tables, d'insertion, d'interrogation, de mise à jour et de suppression de données. 3. Fournir des fonctions avancées telles que les opérations de jointure et les sous-questionnaires. 4. Les performances peuvent être améliorées par l'indexation, l'optimisation des requêtes et le partitionnement de la table. 5. Prise en charge des mesures de sauvegarde, de récupération et de sécurité pour garantir la sécurité et la cohérence des données.

MySQL est un système de gestion de base de données relationnel open source. 1) Créez une base de données et des tables: utilisez les commandes CreateDatabase et CreateTable. 2) Opérations de base: insérer, mettre à jour, supprimer et sélectionner. 3) Opérations avancées: jointure, sous-requête et traitement des transactions. 4) Compétences de débogage: vérifiez la syntaxe, le type de données et les autorisations. 5) Suggestions d'optimisation: utilisez des index, évitez de sélectionner * et utilisez les transactions.

Vous pouvez ouvrir PHPMYADMIN via les étapes suivantes: 1. Connectez-vous au panneau de configuration du site Web; 2. Trouvez et cliquez sur l'icône PHPMYADMIN; 3. Entrez les informations d'identification MySQL; 4. Cliquez sur "Connexion".

Créez une base de données à l'aide de NAVICAT Premium: Connectez-vous au serveur de base de données et entrez les paramètres de connexion. Cliquez avec le bouton droit sur le serveur et sélectionnez Créer une base de données. Entrez le nom de la nouvelle base de données et le jeu de caractères spécifié et la collation. Connectez-vous à la nouvelle base de données et créez le tableau dans le navigateur d'objet. Cliquez avec le bouton droit sur le tableau et sélectionnez Insérer des données pour insérer les données.

MySQL et SQL sont des compétences essentielles pour les développeurs. 1.MySQL est un système de gestion de base de données relationnel open source, et SQL est le langage standard utilisé pour gérer et exploiter des bases de données. 2.MySQL prend en charge plusieurs moteurs de stockage via des fonctions de stockage et de récupération de données efficaces, et SQL termine des opérations de données complexes via des instructions simples. 3. Les exemples d'utilisation comprennent les requêtes de base et les requêtes avancées, telles que le filtrage et le tri par condition. 4. Les erreurs courantes incluent les erreurs de syntaxe et les problèmes de performances, qui peuvent être optimisées en vérifiant les instructions SQL et en utilisant des commandes Explication. 5. Les techniques d'optimisation des performances incluent l'utilisation d'index, d'éviter la numérisation complète de la table, d'optimiser les opérations de jointure et d'améliorer la lisibilité du code.

Vous pouvez créer une nouvelle connexion MySQL dans NAVICAT en suivant les étapes: ouvrez l'application et sélectionnez une nouvelle connexion (CTRL N). Sélectionnez "MySQL" comme type de connexion. Entrez l'adresse Hostname / IP, le port, le nom d'utilisateur et le mot de passe. (Facultatif) Configurer les options avancées. Enregistrez la connexion et entrez le nom de la connexion.

La récupération des lignes supprimées directement de la base de données est généralement impossible à moins qu'il n'y ait un mécanisme de sauvegarde ou de retour en arrière. Point clé: Rollback de la transaction: Exécutez Rollback avant que la transaction ne s'engage à récupérer les données. Sauvegarde: la sauvegarde régulière de la base de données peut être utilisée pour restaurer rapidement les données. Instantané de la base de données: vous pouvez créer une copie en lecture seule de la base de données et restaurer les données après la suppression des données accidentellement. Utilisez la déclaration de suppression avec prudence: vérifiez soigneusement les conditions pour éviter la suppression accidentelle de données. Utilisez la clause WHERE: Spécifiez explicitement les données à supprimer. Utilisez l'environnement de test: testez avant d'effectuer une opération de suppression.

Redis utilise une architecture filetée unique pour fournir des performances élevées, une simplicité et une cohérence. Il utilise le multiplexage d'E / S, les boucles d'événements, les E / S non bloquantes et la mémoire partagée pour améliorer la concurrence, mais avec des limites de limitations de concurrence, un point d'échec unique et inadapté aux charges de travail à forte intensité d'écriture.
