最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

用C++封裝MySQL的API的教程

 更新時(shí)間:2015年05月06日 17:22:32   投稿:goldensun  
這篇文章主要介紹了用C++封裝MySQL的API的教程,包括對語句拼裝器SQLJoin的介紹,需要的朋友可以參考下

其實(shí)相信每個(gè)和mysql打過交道的程序員都應(yīng)該會(huì)嘗試去封裝一套mysql的接口,這一次的封裝已經(jīng)記不清是我第幾次了,但是每一次我希望都能做的比上次更好,更容易使用。

先來說一下這次的封裝,遵守了幾個(gè)原則,其中部分思想是從python借鑒過來的:

    1.簡單

    簡單,意味著不為了微小的效率提升,而去把接口搞的復(fù)雜。因?yàn)楸旧頂?shù)據(jù)庫存儲效率的瓶頸并不是那一兩次內(nèi)存copy,代碼中隨處可以看到以這個(gè)為依據(jù)的設(shè)計(jì)。
    2.低學(xué)習(xí)成本

    使用一套新庫通常意味著投入學(xué)習(xí)成本,而這次的封裝并沒有像django那樣實(shí)現(xiàn)一套完整的模型系統(tǒng),也沒有做soci那樣的語法分析器,我選擇最簡單易懂的方式:做sql語句拼接器,所以對習(xí)慣了使用原生mysql api的朋友,學(xué)習(xí)成本很低
    3.模塊化

    代碼實(shí)際包括了兩個(gè)模塊,一個(gè)是mysql client端的封裝,一個(gè)是sql的拼接器,這兩個(gè)模塊是完全獨(dú)立的,調(diào)用者可以任意組合或者獨(dú)立使用。
    4.盡量使用STL以及模板,簡化代碼編寫

    最大的特點(diǎn)就是大量使用了stringstream進(jìn)行類型轉(zhuǎn)化,減少了大量的重復(fù)代碼。

OK,基于以上的簡單介紹,我們先來看一下
一.mysql client端的封裝:

class CMYSQLWrapper
{
 /**
  * @brief 獲取錯(cuò)誤信息
  *
  * @return 錯(cuò)誤信息
  */
 char* GetErrMsg();

 /**
  * @brief 連接MYSQL,已經(jīng)支持了自動(dòng)重連模式,即mysql server關(guān)閉鏈接會(huì)自動(dòng)重連
  *
  * @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 關(guān)閉鏈接并釋放result
  */
 void Close();

 /**
  * @brief 執(zhí)行SQL語句
  *
  * @param strSql  執(zhí)行語句
  * @param result  執(zhí)行結(jié)果
  *
  * @return 0   succ
  *   else  fail
  */
 int Query(const char* strSql);

 /**
  * @brief 針對Read(select)相關(guān)的的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)相關(guān)的Query
  *
  * @param strSql   sql語句
  * @param affectRowsCount 影響的行的個(gè)數(shù)
  *
  * @return 0    succ
  *   else   fail
  */
 int Query(const char* strSql, int& affectRowsCount);


 /**
  * @brief Select時(shí)獲取數(shù)據(jù),記得手工析構(gòu),或者用StMYSQLRes
  *
  * @param result  執(zhí)行結(jié)果
  *
  * @return 0   succ
  *   else  fail
  */
 int Result(MYSQL_RES *&result);

 /**
  * @brief 返回影響行數(shù)
  *
  * @return >0   succ
  *   0   沒有更新
  *   <0   fail
  */
 int AffectedRows();

 /**
  * @brief 主要是將blob轉(zhuǎn)成字符串
  *
  * @param src   blob源
  * @param len   長度
  *
  * @return 轉(zhuǎn)化后的字符串
  */
 string EscStr(const char* src,uint32_t len);

 /**
  * @brief 將字符串中的某些字符轉(zhuǎn)化(如')
  *
  * @param src   字符串
  *
  * @return 轉(zhuǎn)化后的字符串
  */
 string EscStr(const char* src);
};
 
class CMYSQLWrapper
{
 /**
  * @brief 獲取錯(cuò)誤信息
  *
  * @return 錯(cuò)誤信息
  */
 char* GetErrMsg();
 
 /**
  * @brief 連接MYSQL,已經(jīng)支持了自動(dòng)重連模式,即mysql server關(guān)閉鏈接會(huì)自動(dòng)重連
  *
  * @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 關(guān)閉鏈接并釋放result
  */
 void Close();
 
 /**
  * @brief 執(zhí)行SQL語句
  *
  * @param strSql  執(zhí)行語句
  * @param result  執(zhí)行結(jié)果
  *
  * @return 0   succ
  *   else  fail
  */
 int Query(const char* strSql);
 
 /**
  * @brief 針對Read(select)相關(guān)的的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)相關(guān)的Query
  *
  * @param strSql   sql語句
  * @param affectRowsCount 影響的行的個(gè)數(shù)
  *
  * @return 0    succ
  *   else   fail
  */
 int Query(const char* strSql, int& affectRowsCount);
 
 
 /**
  * @brief Select時(shí)獲取數(shù)據(jù),記得手工析構(gòu),或者用StMYSQLRes
  *
  * @param result  執(zhí)行結(jié)果
  *
  * @return 0   succ
  *   else  fail
  */
 int Result(MYSQL_RES *&result);
 
 /**
  * @brief 返回影響行數(shù)
  *
  * @return >0   succ
  *   0   沒有更新
  *   <0   fail
  */
 int AffectedRows();
 
 /**
  * @brief 主要是將blob轉(zhuǎn)成字符串
  *
  * @param src   blob源
  * @param len   長度
  *
  * @return 轉(zhuǎn)化后的字符串
  */
 string EscStr(const char* src,uint32_t len);
 
 /**
  * @brief 將字符串中的某些字符轉(zhuǎn)化(如')
  *
  * @param src   字符串
  *
  * @return 轉(zhuǎn)化后的字符串
  */
 string EscStr(const char* src);
};

代碼中的注釋已經(jīng)描述的很清楚了,語言描述不清楚,我們直接來看一下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的收發(fā)包已經(jīng)很簡潔了,但是sql語句的拼裝卻顯得十分臃腫。所以這個(gè)時(shí)候sql語句拼裝器-SQLJoin閃亮登場!
二.sql語句拼裝器-SQLJoin

class SQLJoin
{
public:
 /**
  * @brief 用流處理的方式,添加一個(gè)列名
  *
  * @param key   列名
  *
  * @return 0
  */
 SQLJoin& operator << (const string& key);

 /**
  * @brief 用流處理的方式,添加一個(gè)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 分割符,默認(rèn)是用',',也可以用and、or之類
  *
  * @return 所有列名-列值
  */
 string pairs(const string& split_str = ",");

 /**
  * @brief 清空所有數(shù)據(jù)
  */
 void clear();
};
 
class SQLJoin
{
public:
 /**
  * @brief 用流處理的方式,添加一個(gè)列名
  *
  * @param key   列名
  *
  * @return 0
  */
 SQLJoin& operator << (const string& key);
 
 /**
  * @brief 用流處理的方式,添加一個(gè)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 分割符,默認(rèn)是用',',也可以用and、or之類
  *
  * @return 所有列名-列值
  */
 string pairs(const string& split_str = ",");
 
 /**
  * @brief 清空所有數(shù)據(jù)
  */
 void clear();
};

看看我們用了SQLJoin之后的代碼應(yīng)該如何:

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();
}

從上面的代碼可以看出,代碼的可維護(hù)性和健壯性得到了很大的提升。

OK,簡單的介紹就是這樣,說的比較簡略,大家有興趣可以直接看代碼,也歡迎給我提意見和建議。代碼下載路徑如下:
mysql_wrapper

明天這份代碼就會(huì)作為數(shù)據(jù)庫訪問層正式進(jìn)入生產(chǎn)環(huán)境的代碼中,因此有什么bug我也會(huì)及時(shí)在這里更新。

相關(guān)文章

  • python pytorch中.view()函數(shù)的用法解讀

    python pytorch中.view()函數(shù)的用法解讀

    這篇文章主要介紹了python pytorch中.view()函數(shù)的用法,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • Python  中的pass語句語法詳析

    Python  中的pass語句語法詳析

    這篇文章主要介紹了Python 中的pass語句語法詳析,pass是一種空操作(null operation),解釋器執(zhí)行到它的時(shí)候,除了檢查語法是否合法,什么也不做就直接跳過
    2022-07-07
  • python 實(shí)現(xiàn)彈球游戲的示例代碼

    python 實(shí)現(xiàn)彈球游戲的示例代碼

    這篇文章主要介紹了python 實(shí)現(xiàn)彈球小游戲,幫助大家更好的理解和學(xué)習(xí)python,感興趣的朋友可以了解下
    2020-11-11
  • python基礎(chǔ)之并發(fā)編程(一)

    python基礎(chǔ)之并發(fā)編程(一)

    這篇文章主要介紹了詳解python的并發(fā)編程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-10-10
  • python中append函數(shù)用法講解

    python中append函數(shù)用法講解

    在本篇文章里小編給大家整理的是一篇關(guān)于python中append函數(shù)用法講解內(nèi)容,有興趣的朋友們可以學(xué)習(xí)下。
    2020-12-12
  • jupyter 導(dǎo)入csv文件方式

    jupyter 導(dǎo)入csv文件方式

    這篇文章主要介紹了jupyter 導(dǎo)入csv文件方式,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-04-04
  • PyautoGui常用教程(一篇掌握)

    PyautoGui常用教程(一篇掌握)

    這篇文章主要介紹了PyautoGui常用教程(一篇掌握),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • 分享8點(diǎn)超級有用的Python編程建議(推薦)

    分享8點(diǎn)超級有用的Python編程建議(推薦)

    這篇文章主要介紹了分享8點(diǎn)超級有用的Python編程建議(推薦),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-10-10
  • Python csv文件記錄流程代碼解析

    Python csv文件記錄流程代碼解析

    這篇文章主要介紹了Python csv文件記錄流程代碼解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • Python實(shí)現(xiàn)連接MySql數(shù)據(jù)庫及增刪改查操作詳解

    Python實(shí)現(xiàn)連接MySql數(shù)據(jù)庫及增刪改查操作詳解

    這篇文章主要介紹了Python實(shí)現(xiàn)連接MySql數(shù)據(jù)庫及增刪改查操作,結(jié)合實(shí)例形式詳細(xì)分析了Python安裝PyMySQL模塊及使用PyMySQL模塊進(jìn)行mysql數(shù)據(jù)庫的連接、增刪改查等相關(guān)操作技巧,需要的朋友可以參考下
    2019-04-04

最新評論

德令哈市| 阿鲁科尔沁旗| 泊头市| 伊春市| 七台河市| 阳东县| 郁南县| 龙州县| 江达县| 昆明市| 平凉市| 贡觉县| 阳东县| 林口县| 定结县| 织金县| 阳山县| 榆社县| 西昌市| 利津县| 磐石市| 榆林市| 罗定市| 安新县| 新田县| 怀柔区| 双桥区| 洪湖市| 陈巴尔虎旗| 北川| 宜州市| 唐海县| 濮阳县| 建湖县| 剑川县| 将乐县| 苗栗市| 宜都市| 股票| 寻乌县| 贵定县|