【原創】7. MYSQL++中的查詢結果獲取(各種Result類型)


在本節中,我將首先介紹MYSQL++中的查詢的幾個簡單例子用法,然后看一下mysqlpp::Query中的幾個與查詢相關的方法原型(重點關注返回值),最后對幾個關鍵類型進行解釋。

 

1. MYSQL++的查詢實例

下面的兩個例子分別是STORE(所有數據一次性從服務器拉到本地緩存)和USE(將數據一條一條從服務器拉到本地)的使用方式,其中STORE內部實質就是mysql_store( ),而USE實質就是調用了mysql_use( )。

說明,下面的例子雖然使用的都是最為基本的查詢過程(即沒有使用template sql或者SSQLS),但是這個並不影響我們的討論,因為遍歷結果集的過程是一致的。

 

STORE

mysqlpp::Query query = conn.query("select item from stock");
mysqlpp::StoreQueryResult res = query.store();

mysqlpp::StoreQueryResult::const_iterator it;
for (it = res.begin(); it != res.end(); ++it) 
{

    mysqlpp::Row row = *it;

    // 第一列 row[0]
    // 第二列 row[1]
}

 

USE

mysqlpp::Query query = conn.query("select * from stock");
mysqlpp::UseQueryResult res = query.use();
while (mysqlpp::Row row = res.fetch_row()) 
{
    row["item"];
    row["num"];
}
// Check for error: 
// can't distinguish "end of results" and
// error cases in return from fetch_row() otherwise
if (conn.errnum()) 
{
    cout << "Error in fetch_row";
}

從上面的兩個例子中我們大致可以看出來,整個結果集的查詢過程就是針對相匹配的Result類型,找到ROW,然后逐行或者跳躍着查找。

 
 
        

2. Result相關類型的使用場合

首先讓我們回顧mysqlpp::Query中提到的幾個方法,以及他們的返回值。以下部分內容直接摘自關於mysqlpp::Query的介紹的內容。

為了講述方便,我們先來看一下在result.h(Declares classes for holding information about SQL query)中所定義的各種類型的關系。這幾個類型后面會仔細說明。

image_thumb[2]

1)

bool mysqlpp::Query::exec(const std::string& str);

這里返回的是bool,表示的是“語句是否執行成功”,我認為適合於那種update, delete,insert,且都不關心有多少rows被touch的情況。

 
 
        

2)

SimpleResult mysqlpp::Query::execute();

這里的SimpleResult正如其名,其中只有如下信息

  • the last value used for an AUTO_INCREMENT field
    (ulonglong insert_id() const)
  • the number of rows affected by the query
    (ulonglong rows( ) const)
  • any additional information about the query returned by the server(const char* info( ) const)

 

3)

UseQueryResult mysqlpp::Query::use();

由於use的語義類似於使用游標,也就是支持一行一行地拉出內容,所以UseQueryResult 也就自然而然地支持一些關於fetch row的功能。

 

4)

StoreQueryResult mysqlpp::Query::store();

StoreQueryResult它本身就是從vector<Row>繼承而來,所以它就是vector。所以用戶程序可以直接使用下標的形式來獲取所有的ROW。這也就是說在這個store之后,所有的ROW的內容都在了這個vecor<Row>里面了。

 

3. Result相關類型解析

與Result相關的類型主要集中在result.h和result.cpp。

 

1) SimpleResult

這個類型非常簡單,是一個比較單純的類型,並沒有父類。主要的成員變量有3個,分別是

 

// last value used for an AUTO_INCREMENT field
ulonglong insert_id_;

// the number of rows affected by the query
ulonglong rows_;

// any additional information about the query returned by the server
std::string info_;

 

成員方法也比較單純,就是對上述幾個字段的GET,構造函數就是對上述幾個字段的SET。

以SimpleResult mysqlpp::Query::execute();為例,讓我們來看一下MYSQL++是如何設置這個SimpleResult。
image

再來看一下Query::insert_id( ), Query::affected_rows( ), Query::info( ),這幾個方法都直接delegate DBDriver的相關函數,直接返回了結果而已。

 

2) ResultBase

這個類型是StoreQueryResult和UseQueryResult的父類型,該類型其實沒有特別的含義,只是作為一個common methods的container而已。但是該類型提供的幾乎所有的public methods都是和fields有關的,包括了

  • 根據index查找field;
  • 根據name查找field;
  • 根據index查找到field的名字和屬性類型;
  • 獲取當前所在的field(ResultBase內部會有一個mutable的index名為current_field_用於指明當前fetch_field的是哪一個field,在fetch_field中該index會自增)

該類型的核心成員有如下幾個

  • Fields(std::vector<Field>) 類型的 fields_
  • FieldNames (繼承自std::vector<std:: string>)類型的 names_
  • FieldTypes ( 繼承自std::vector<mysql_type_info>)類型的types_

其中FieldNames和FieldTypes都是被RefCountedPointer包裹着,估計這樣做能夠節省空間。關於Field類型在后續進行介紹。至於剛才說的幾個找field的操作,看着這幾個核心成員的類型還是比較好理解的。不就是在vector中不找。

需要額外關注的是以下這個最主要的構造函數

image

以下幾點需要注意,

  • names_和types_在new出來之后是不需要顯式delete的,因為他們都在智能指針RefCountedPointer包裹着。
  • 成員初始化列表中的 fields_(Fields:: size_type(…)) 這一句其實調用的是
explicit std::vector::vector (size_type n, const value_type& val = value_type(), const allocator_type& alloc = allocator_type());
  • 從以上構造函數可以看到,其實關於Field的信息還是從DBDriver中拿到的,然后關於FieldNames和FieldTypes的信息,則是通過這兩個類型自身的構造函數給實現的(其實就是收到ResultBase*,然后遍歷其中的成員變量 fields_ 再各求所需罷了。
  • 為什么要有重新將指示field_當前index的指針重置的過程(dbd->field_seek(res, 0))?這是因為方便這個DBDriver再次循環訪問這些fields。

 

3) StoreQueryResult

該類型是同時集成了ResultBase和vecor<Row>類型(請注意了,這個Result居然是一個vecor<Row>!)文檔中說,該類型hold results from a SQL query that returns rows: a specialization of std::vector holding Row objects in memory so you get random-access semantics.

說白了,該類型在繼承了ResultBase之后,只有以下這個構造函數是比較要緊的了。

image

有以下幾點需要說明

  • StoreQueryResult繼承自std::vector<Row>
  • 在成員初始化列表中,首先調用ResultBase的構造函數
  • list_type是std::vector<Row>的typedef,所以在list_type(…)這一行,直接根據DBDriver返回的結果的rows的數量就布置好了vector的長度。
  • MYSQL_ROW是MYSQL自帶的結構類型(定義域mysql.h中,typedef char **MYSQL_ROW;)
  • dbd->fetch_row(MYSQL_RES*)應該只是包裝了mysql_fetch_row(MYSQL_RES*)這個MySql C API,而dbd->fetch_lengths(MYSQL_RES*)其實包裝的是mysql_fetch_lengths(MYSQL_RES*)這個MYSQL C API,他獲取的是整個row的對應的所有field的長度。
  • 這一次Query的結果在全部拷貝完之后就釋放了(dbd->free_result(res);)

 

 

 

 

 

如此一來,所有我們需要的信息都通過構造一個mysqlpp::Row對象來實現了。關於mysqlpp::Row的具體說明請看下文。

 

4) UseQueryResult

 

該類型拓展於ResultBase類型。根據MYSQL++ user document的說法,UseQueryResule適用於For these large result sets,a “use” query tells the database server to send the results back one row at a time, to be processed linearly.

該類型的方法比StoreQueryResult豐富多了,主要體現在:

  • 可以順序讀取行(mysqlpp::Row fetch_row() const;或者MYSQL_ROW fetch_raw_row() const;)
  • 可以獲取當前行的各個field的信息(const Field& fetch_field() const; const Field& fetch_field(Fields::size_type i) const)
  • 可以獲取當前行的所有fields的長度(const unsigned long* fetch_lengths() const;)

值得注意的是,UseQueryResult有一個成員變量

mutable RefCountedPointer<MYSQL_RES> result_;

需要強調的有兩點

  • MYSQL_RES是 MYSQL C API 中的用於做為資源的結構體,獲取一行的函數mysql_fetch_one_row的參數就是MYSQL_RES*
  • RefCountedPointer是一個智能指針,但是就在定義這些result類型的result.h中,作者將其針對MYSQL_RES進行了具化,即

image

很顯然,這個是為了在ref count為0時自動調用析構器而准備的,該Destroyer使用mysql_free_result來銷毀這里的result_,從而代替默認的delete操作。

 

接下來,我們來具體看幾個函數的實現。

  • 構造函數

image

 

  • 獲取fields的信息

image

image

請注意,這個result_是一個RefCountedPointer<MYSQL_RES>,所以調用的raw方法將會返回MYSQL_RES*

 

  • 獲取一行數據

核心的做法就是利用MYSQL_ROW  DBDriver::fetch_row(MYSQL_RES* res) const。其實質也就是調用了mysql_fetch_one_row( )這個C API。然后直接生成一個mysqlpp::Row對象,返回。

image


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM