MySQL++ V3.1.0 用户手册7
MySQL++是一个针对MySQL C API的C++封装。它的目的是提供一个类似STL容易一样简单易用的接口,帮助你有效的避免在代码中使用复杂的SQL语句。
5.5. 更改数据
更改一个SSQLS数据和insert它一样的简单,下面是一个例子 examples/ssqls3.cpp
#include "cmdline.h"
#include "printdata.h"
#include "stock.h"
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
// 从命令行获取数据库参数
const char* db = 0, *server = 0, *user = 0, *pass = "";
if (!parse_command_line(argc, argv, &db, &server, &user, &pass))
{
return 1;
}
try
{
// 建立一个和数据库服务器的连接
mysqlpp::Connection con(db, server, user, pass);
// 创建一个查询
mysqlpp::Query query = con.query(
"select * from stock where item = \"Nürnberger Brats\"");
// 保存查找结果,如果失败则抛出一个异常
mysqlpp::StoreQueryResult res = query.store();
if (res.empty()) {
throw mysqlpp::BadQuery("UTF-8 bratwurst item not found in "
"table, run resetdb");
}
// 因为可能结果中只有一行数据,而我们的STL容器中没有保存指针。我们可以使用一个SSQLS保存第一行的stock对象
stock row = res[0];
// 创建一个副本,让我们记录下来需要更新的结果列有哪些
stock orig_row = row;
// 更换stock对象的item字段属性。
row.item = "Nuerenberger Bratwurst";
// 我们开始更新stock表内的指定结果行
query.update(orig_row, row);
// 显示这个将被执行的查询语句
cout << "Query: " << query << endl;
// 因为执行这条查询不会有结果集需要返回,可以使用 execute()
query.execute();
// 输出新表内结构
print_stock_table(query);
}
catch (const mysqlpp::BadQuery& er) {
cerr << "Query error: " << er.what() << endl;
return -1;
}
catch (const mysqlpp::BadConversion& er) {
cerr << "Conversion error: " << er.what() << endl <<
"\tretrieved data size: " << er.retrieved <<
", actual size: " << er.actual_size << endl;
return -1;
}
catch (const mysqlpp::Exception& er) {
cerr << "Error: " << er.what() << endl;
return -1;
}
return 0;
}
在执行这个例子后不要忘记运行 resetdb 重置数据库。
5.6. 使用set容器保存SSQLS
如果我们需要对结果集进行一个大小排序,我们可能需要使用STL中的set容器。它默认定义了一个 operator < 操作符重载。SSQLS给予了这方面的支持,请参见例子 examples/ssqls4.cpp:
#include "cmdline.h"
#include "printdata.h"
#include "stock.h"
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
const char* db = 0, *server = 0, *user = 0, *pass = "";
if (!parse_command_line(argc, argv, &db, &server, &user, &pass)) {
return 1;
}
try {
// 连接数据库服务器
mysqlpp::Connection con(db, server, user, pass);
// 取出stock表内所有行数据并保存在一个STL的set容器内。非常简单对吧,就和保存在 vector 中没什么两样,这是因为SSQLS对象都支持比较操作。
mysqlpp::Query query = con.query("select * from stock");
set<stock> res;
query.storein(res);
// 显示结果集
print_stock_header(res.size());
set<stock>::iterator it;
cout.precision(3);
for (it = res.begin(); it != res.end(); ++it) {
print_stock_row(it->item.c_str(), it->num, it->weight,
it->price, it->sdate);
}
// 使用set的find方法,根据一个item名称查找一个item。这里同样默认使用了SSQLS的比较操作。
it = res.find(stock("Hotdog Buns"));
if (it != res.end()) {
cout << endl << "Currently " << it->num <<
" hotdog buns in stock." << endl;
}
else {
cout << endl << "Sorry, no hotdog buns in stock." << endl;
}
}
catch (const mysqlpp::BadQuery& er) {
cerr << "Query error: " << er.what() << endl;
return -1;
}
catch (const mysqlpp::BadConversion& er) {
cerr << "Conversion error: " << er.what() << endl <<
"\tretrieved data size: " << er.retrieved <<
", actual size: " << er.actual_size << endl;
return -1;
}
catch (const mysqlpp::Exception& er) {
cerr << "Error: " << er.what() << endl;
return -1;
}
return 0;
}
因为在SSQLS内已经进行了声明,所以find()函数可以正常使用。我们可以重载这个函数。通常来说,我们进行两个SSQLS进行比对排序的时候,会取它的第一个字段进行比较。在数据库中,这个字段也
通常作为主键。因此,我们要注意数据库表内字段的设计,第一个字段作为主键更加合适。
5.7. 修改表名
如果你使用查询创建了一个SSQLS的表,默认情况下,数据库会创建一个和SSQLS结构类型名完全一致的一个表名。如果你觉得这样不合适,你可以这样修改一个表名:
stock::table(“MyStockData”);
你也可以在与创建表实例的时候修改实例名称:
stock s; s.instance_table(“AlternateTable”);
当你在一个多表数据库中创建SSQLS定义时很有用,能保证你各个表的名称不同。这个特性将保证你不得不为每个表创建一个不同名称的SSQLS。
严格来说,你仅仅需要在多线程项目中使用这个特性。如果在单线程中,你可以在使用每个SSQLS对象之前修改静态表名称,这很安全的。
5.8. 在多个模块中使用一个SSQLS
如果你需要在多个模块使用一个SSQLS结构,建议你可以在一个头文件中定义这个SSQLS结构,将会很方便的使用它。但是这样的话,你可能引发一些问题。因为每个SSQLS结构中都会保存一些静态常用数
据(例如表名和字段名列表),如果你在多个模块里使用#include包含这个头文件的话,你将会在链接时候得到一个重复定义的错误。 解决这个问题的方法是:你在所有引用模块中都定义一个预处理宏 MYSQLPP_SSQLS_NO_STATICS,但是保留其中一个文件不要定义该宏。如果定义了这个宏,将意味着在该宏之后的所有SSQLS内静态成员
变量将无效。 我们假设有一个文件 my_ssqls.h 内包含了 sql_create_N 宏,这个宏定义了一个 SSQLS.而这个SSQLS被至少两个模块使用。其中一个我们将 foo.cpp ,另外一个叫 my_ssqls.cpp 。我们可以随便选
择一个文件,认为它“拥有”了这个SSQLS,而另外一个文件,仅仅是“使用”了这个SSQLS。那么我们可以如下使用:
// 文件foo.cpp,我们假设它仅仅是使用了SSQLS,而没有拥有这个SSQLS #define MYSQLPP_SSQLS_NO_STATICS #include “my_ssqls.h”
// 文件 my_ssqls.cpp,我们假设它拥有了这个SSQLS,则它不需要额外的宏定义,只需要正常包含头文件即可 #include “my_ssqls.h”
如果我们不止两个模块使用了这个SSQLS,我们需要在大部分“使用”这个SSQLS的文件前增加额外的宏定义。此时我们可以有个更简单的方法。
// 文件 my_ssqls.h: #if !defined(EXPAND_MY_SSQLS_STATICS)
define MYSQLPP_SSQLS_NO_STATICS
#endif sql_create_X(Y, Z….) // SSQLS的定义
// 文件 foo.cpp, 一个普通的SSQLS“使用者” #include “my_ssqls.h”
// 文件 my_ssqls.cpp, 特殊的唯一的那个SSQLS“拥有者” #define EXPAND_MY_SSQLS_STATICS #include “my_ssqls.h”
这样我们可以免除对大量的“使用者”定义那个宏,只要“拥有者”定义一个宏即可。