1. 程式人生 > >Mysql++學習(五)------專用SQL結構

Mysql++學習(五)------專用SQL結構

專用SQL結構(SSQLS) 特性可以讓你很輕易的定義用來匹配SQL表的C++結構.最通俗的理解:對於SQL表中的每一個欄位,SSQLS結構都有一個變數與之對應.但是,MySQL++內部也會使用SSQLS的其他方法,操作符來提供簡潔的功能.

要定義SSQLSes,需要使用定義在ssqls.h中的巨集,這也是MySQL++唯一沒有自動加入mysql++.h的標頭檔案.

sql_create

假如你有如下SQL表

CREATE TABLE stock (
    item CHAR(30) NOT NULL,
    num BIGINT NOT NULL,
    weight DOUBLE NOT NULL,
    price DECIMAL(6,2) NOT NULL,
    sdate DATE NOT NULL,
    description MEDIUMTEXT NULL)

你可以定義一個對應的C++結構如下

sql_create_6(stock, 1, 6,
    mysqlpp::sql_char, item,
    mysqlpp::sql_bigint, num,
    mysqlpp::sql_double, weight,
    mysqlpp::sql_decimal, price,
    mysqlpp::sql_date, sdate,
    mysqlpp::Null<mysqlpp::sql_mediumtext>, description)

stock結構宣告有著相同名字的資料成員對應SQL的每一列,同時該結構還包含一些成員函式,操作符以及隱藏資料成員.

sql_create_# call呼叫中,欄位名稱前面的是C++資料型別.

有時候你必須使用MySQL++的特殊資料型別來對應資料結構,考慮description欄位的型別,MySQL++的 sql_mediumtext型別就是std::string的一個等價.

通常結構如下:

sql_create_#(NAME, COMPCOUNT, SETCOUNT, TYPE1, ITEM1, ... TYPE#, ITEM#)

“#”是變數的數量,“NAME”是你希望建立的結構名稱,“TYPEx

”是變數型別,“ITEMx”是變數名稱.

SSQLS對比和初始化

 sql_create_#添加了一些成員函式和操作來支援SSQLS物件之間的比較,COMPCOUNT數量表示用來比較的欄位的個數,上面例子中為1,意味著只比較item欄位,將主鍵放到最前面並且指定比較個數,可以很好利用這一特性.sql_create_#建立的第二個引數是SETCOUNT,如果非0,它將增加一個構建函式和一個set()成員函式,該函式接受指定引數來設定結構第N個欄位的值.

sql_create_6(stock, 1, 2,
    mysqlpp::sql_char, item,
    mysqlpp::sql_bigint, num,         
    mysqlpp::sql_double, weight,  
    mysqlpp::sql_decimal, price,  
    mysqlpp::sql_date, sdate,
    mysqlpp::Null<mysqlpp::sql_mediumtext>, description)
    
stock foo("Hotdog", 52);

COMPCOUNT 和SETCOUNT 的值不可以相等,如果相等,會導致產生引數列表相同的兩個構建函式.

查詢資料

mysqlpp::Query query = conn.query("select item, description from stock");
vector<stock> res;
query.storein(res);

for(auto i = res.begin(); i != res.end(); i++)
{
    cout << i->item << '\t' ;
    cout << i->description << endl;
}

在定義了SSQLS結構後,可以直接將查詢結構放入相應容器,進行各種操作.

增加資料

//create a stock object
stock new_row(
         "Hot dog", 100, 1.5, 130, mysqlpp::sql_date("2014-11-30"), mysqlpp::null
     );
//execute a query
mysqlpp::Query query = conn.query();
query.insert(new_row);
        
cout << "Query: " << query << endl;
query.execute();

首先,建立一個要插入的SSQLS物件,然後,建立查詢物件,最後執行

批量插入也很容易,只要加一個迴圈即可

vector<stock> lots_of_stuff;

...populate the vector somehow...

query.insert(lots_of_stuff.begin(), lots_of_stuff.end()).execute();

MySQL對於SQL查詢長度有所限制,預設最大為1M.因此,使用insert批量插入時,容器中的查詢長度可能超過限制.

在這種情況下使用Query::insertfrom(),它是INSERT和execute()的組合.

mysqlpp::Query::MaxPacketInsertPolicy<> insert_policy(1000);

query.insertfrom(stock_vector.begin(), stock_vector.end(), insert_policy);

它採用最大包策略,該例中指定一個查詢最大為1000,它會自動檢測查詢是否超過限制,然後分割執行查詢.

還有兩個策略類:MaxPacketInsertPolicy和RowCountInsertPolicy,它們都提供了在查詢長度在一定範圍類的策略方法,如果不適用,也可以研究下lib/insertpolicy.*,然後自己寫策略類.策略類本質都是些類模板.

修改資料

//execute a query
mysqlpp::Query query = conn.query("select * from stock ");
query << "where item = " << mysqlpp::quote << "abc";
//get query result in a storeResult
mysqlpp::StoreQueryResult res = query.store();
if(res)
{
        stock row = res[0];
        stock orig_row = row;
        row.item = "hamburger";
        query.update(orig_row, row);
        cout << "Query : " << query <<endl;
        query.execute();
}

首先取出要修改的記錄,然後修改相應欄位,再用新欄位代替原欄位,執行替換操作.

用關聯容器來存放SSQLS

//execute a query
mysqlpp::Query query = conn.query("select * from stock ");
//get query result in a storeResult
set<stock> res;
query.storein(res);
if(res.size())
{
       for(auto i = res.begin(); i != res.end(); ++i)
       {
            cout << i->item.c_str() << '\t' << i->num << '\t' << i->price << endl;
       }
}

改變表名

預設情況下,資料庫表和SSQLS結構擁有相同的表名稱.你也可以用如下方法全域性修改查詢中使用的表名.

stock::table("MyStockData");

也可以修改每個例項中的表名

stock s;

s.instance_table("AlternateTable");

在多個模組中使用SSQLS

// File my_ssqls.h:
#if !defined(EXPAND_MY_SSQLS_STATICS)
#   define MYSQLPP_SSQLS_NO_STATICS
#endif
sql_create_X(Y, Z....) // the SSQLS definition
// File foo.cpp, a mere user of the SSQLS:
#include "my_ssqls.h"
// File my_ssqls.cpp, which owns the SSQLS:
#define EXPAND_MY_SSQLS_STATICS
#include "my_ssqls.h"

利用SSQLS的內部構件

sql_create巨集為每個SSQLS定義了一些有用的方法,這些方法大多用於庫內部,以下偽碼展示了一些用法.

// Basic form
template <class Manip>   
stock_value_list<Manip> value_list(cchar *d = ",",
  Manip m = mysqlpp::quote) const;  

template <class Manip>   
stock_field_list<Manip> field_list(cchar *d = ",",   
  Manip m = mysqlpp::do_nothing) const;  

template <class Manip>   
stock_equal_list<Manip> equal_list(cchar *d = ",",
  cchar *e = " = ", Manip m = mysqlpp::quote) const;  


// Boolean argument form
template <class Manip>
stock_cus_value_list<Manip> value_list([cchar *d, [Manip m,] ]   
  bool i1, bool i2 = false, ... , bool i5 = false) const;  

// List form  
template <class Manip>
stock_cus_value_list<Manip> value_list([cchar *d, [Manip m,] ]  
  stock_enum i1, stock_enum i2 = stock_NULL, ...,
  stock_enum i5 = stock_NULL) const;  

// Vector form  
template <class Manip>
stock_cus_value_list<Manip> value_list([cchar *d, [Manip m,] ]  
  vector<bool> *i) const;  

...Plus the obvious equivalents for field_list() and equal_list()

下面例子演示通過查詢的一條記錄來構建一個查詢

在C++和SQL中使用不同的欄位名稱

sql_create_complete_5(stock, 1, 5,   
    mysqlpp::sql_char, m_sItem, "item",
    mysqlpp::sql_bigint, m_nNum, "num",
    mysqlpp::sql_double, m_fWeight, "weight",
    mysqlpp::sql_decimal, m_fPrice, "price",
    mysqlpp::sql_date, m_Date, "sdate")

繼承自一個SSQLS

sql_create_2(
  Base, 1, 2,
  mysqlpp::sql_varchar, a,
  mysqlpp::sql_int, b
);

class Derived : public Base
{
public:
  // default constructor[14]
  Derived() :
  Base()
  {
  }

  // for-comparison constructor[15]
  Derived(const mysqlpp::sql_varchar& _a) :
  Base(_a)
  {
  }

  // full creation constructor
  Derived(const mysqlpp::sql_varchar& _a, const mysqlpp::sql_int& _b) :
  Base(_a, _b)
  {
  }

  // population constructor[16]
  Derived(const mysqlpp::Row& row) :
  Base(row)
  {
  }

  // functionality added to the SSQLS through inheritance
  bool do_something_interesting(int data);
};