poco mysql 中文_Poco数据库操作用户手册(一)

一个简单的例子

POCO

Data提供了一个抽象的数据层,以供用户方便的与不同的数据库交互,以下是一个完整的实例:

[code]

#include

"Poco/Data/Common.h"

#include

"Poco/Data/SQLite/Connector.h"

#include

using namespace

Poco::Data;

void init()

{

SQLite::Connector::registerConnector();

}

void shutdown()

{

SQLite::Connector::unregisterConnector();

}

int main(int argc, char*

argv[])

{

init();

Session ses("SQLite", "sample.db");

int count = 0;

ses << "SELECT COUNT(*) FROM PERSON",

into(count), now;

std::cout << "People in DB " <<

count;

shutdown();

}

[/code]

以上例子非常清晰明了,Poco/Data/Common.h包含了一些常用的数据库相关的引用,使用SQLite::Connector注册SQLite连接器后,我们可以通过SessionFactory创建SQLite会话。Session的构造函数包括两个参数:

[code]

Sesssion ses("SQLite",

"sample.db");

[/code]

与以下用法等价:

[code]

Session ses(SessionFactory::instance()::create("SQLite",

"sample.db"));

[/code]

操 作符<

statements给当前session,into(count)用于将SQL的查询结果保存到count变量中。在SQL

Statement后面城需以now结尾,否则SQL语句不会立即执行。为便于代码阅读,可以使用时带上Poco::Data命令空间。(例如:ses

<< "SELECT COUNT(*) FROM PERSON", Poco::Data::into(count),

Poco::Data::now; ) (http://www.libpoco.com翻译,转载请注明!)

以下手册分这几部分进行介绍:

a.

创建会话(session)

b. 从DB中读写数据(神奇的into,

use)

c. 使用statements

d.

使用容器(Collection) (数据,集合...)

e. 使用limit限定

f.

如何使用复杂的数据类型(如何将一个C++对象映射到数据库的表

创建会话

通常都是通过会话工厂(SessionFactory)的create方法来创建会话(session),

或通过带两个参数的session构造函数来创建。

Session create(const std::string&

connectorKey, const std::string&

connectionString);

第 一个参数用于指定数据库类型,其中POCO内置SQLite支持,

可通过ODBC驱动支持Oracle, SQLite, DB2,

SQLServer和PostgreSQL。第二个参数用于指定数据库连接参数(不同类型的数据库,参数格式不一样)。对于SQLite数据库来说,第二

个参数就是数据库文件的路径。

从DB中读写数据

可将变量的值插入到DB当中。假设数据库中有一个表,只有一个forename字段:

ForeName (Name

VARCHAR(30))

如果我们需要插入一个forename,可简单如下实现:

std::string

aName("Peter");

ses << "INSERT INTO

FORENAME VALUES(" << aName << ")", now;

虽然以上可以实现插入,但有个更好的方法就是使用占位符,并使用use语句将变量与占位符绑定,在执行时会用变量值替换占位符。占位符以

: 引导,使用占位符重写上面的例子如下:

std::string

aName("Peter");

ses << "INSERT INTO

FORENAME VALUES(:name)", use(aName), now;

在此例子当中,使用值Peter替换:name占位符。

在“statements”章节,将看到更多更好的使用占位符的方法。

从数据库获取数据的方法类似,可以使用 into

语句将数据库中的数据映射到C++中的对象,同时也支持使用一个默认值来替换数据库中的null.

std::string aName;

ses << "SELECT NAME FROM

FORENAME", into(aName), now; // aName的默认值为空字符串

ses << "SELECT NAME FROM

FORENAME", into(aName, "default"), now;

此外,也可以在一条SQL语句中同时使用use,into语句:

std::string aName;

std::string

match("Peter")

ses << "SELECT NAME FROM

FORENAME WHERE NAME=:name", into(aName), use(match),

now;

poco_assert (aName ==

match);

通常,数据库中的表不会这么简单,一般会有多个字段,因此也可以在SQL中使用多个into/use.

假设有一个Person表包括age, firstname,

lastname:

std::string

firstName("Peter";

std::string

lastName("Junior");

int age = 0;

ses << "INSERT INTO PERSON

VALUES (:fn, :ln, :age)", use(firstName), use(lastName), use(age),

now;

ses << "SELECT (firstname,

lastname, age) FROM Person", into(firstName), into(lastName),

into(age), now;

此处需要注意的是into/use的顺序问题,第一个占位符对应第一个use,

第二个对应第二个等等。into语句也是类似,上例中的firstname也将输出到第一个into(firstname)当中。(http://www.libpoco.com翻译,转载请注明!)

处理NULL值

数据库中的字段值可以是NULL值,为应付NULL值,

into语句允许定义一个默认值,比如,假设age字段是可选的,我们可以通过into(age,-1)来设置age为NULL时返回-1:

std::string

firstName("Peter";

std::string

lastName("Junior");

int age = 0;

ses << "INSERT INTO PERSON

VALUES (:fn, :ln, :age)", use(firstName), use(lastName), use(age),

now;

ses << "SELECT (firstname,

lastname, age) FROM Person", into(firstName), into(lastName),

into(age, -1), now;

你也可以初始化age=-1来达到同样的效果,此方法不适合容器(Collection)类型,你必须使用第二个参数来初始化。否则,变量将按编译器来决定初始值。

使用Statements

我们已经在前面的章节注意到statement术语。你也许以为我们只使用了session对象,但事实上,我们已经接触到了statement,

让我们来看看session对象<

template

Statement Session::operator

<< (const T& t)

忽略template语句,操作符<

给任何变量,只是简单的使用now直接执行了statement,之后statement就消灭了。下面的例子将使用一个变量来保存statement变

量:

std::string

aName("Peter");

Statement stmt = ( ses <<

"INSERT INTO FORENAME VALUES(:name)", use(aName) );

注意右边的表达式必须要用括号包围,否则将无法编译。如果觉得上面的语法不太好看,可参考以下用法:

Statement

stmt(ses);

stmt << "INSERT INTO

FORENAME VALUES(:name)", use(aName);

将statement对象赋给一个变量后,我们控制statement啥时候执行:

std::string

aName("Peter");

Statement stmt = ( ses <<

"INSERT INTO FORENAME VALUES(:name)", use(aName) );

stmt.execute();

poco_assert

(stmt.done());

将调用execute方法后,将在数据库中执行上面的insert语句。stmt.done()可用来验证statement是否完全执行。

预定义的statement

未加now的statement即为预定义的statement:

Statement stmt = ( ses <<

"INSERT INTO FORENAME VALUES(:name)", use(aName) );

预定义statement的优势是可以优化性能,比如以下的循环:

std::string

aName();

Statement stmt = ( ses <<

"INSERT INTO FORENAME VALUES(:name)", use(aName) );

for (int i = 0; i < 100;

++i)

{

aName.append("x");

stmt.execute();

}

以上例子不需要创建和解析statement

100次,只需一次即可。使用use和占位符,可实现插入100个不同的值到数据库。当然,如果真的要插入大量数据到数据库,还有其它更好的方法。

特别注意

use语句使用的是变量的引用,因此,只可使用变量,不可以使用常量值。以下代码将失败(不同的编译器和环境会有不同的处理结果)

Statement stmt = (ses <<

"INSERT INTO PERSON VALUES (:fn, :ln, :age)", use("Peter"),

use("Junior"), use(4)); //错误!

stmt.execute();

以上常量值Petter,Junior,4

必须赋给一个变量,否则将在执行时出错。

配合容器使用

如需一次处理多个值,需要使用容器(collection)类。默认支持以下容器类:

a. vector(数组): 无特别要求

b. set:

类型需要支持

c.  multiset:

需支持

d. map:

需支持()操作符,并且按key返回对象,注意:重复的key/value将忽略

e. multimap:

需支持()操作符,并按key返加对象.

以下是通过数组来批量插入DB的例子:

std::string

aName("");

std::vector data;

for (int i = 0; i < 100;

++i)

{

aName.append("x");

data.push_back(aName);

}

ses << "INSERT INTO

FORENAME VALUES(:name)", use(data), now;

对于set,multiset也可按上面的方式插入,但map,multimap不行(std::string没有()操作符).

同时需注意,use语句要求容量为非空(non-empty collections)!

现在来看看以下例子:

std::string aName;

ses << "SELECT NAME FROM

FORENAME", into(aName), now;

在前面的例子中是正常的,是因为数据库的此表只有一行记录。如果数据库中有多行记录,我们只提供了一个字符串变量来存储的话,上面的例子将失败并抛出异常。可用以下的方式改进:

std::vector names;

ses << "SELECT NAME FROM

FORENAME", into(names), now;

当然,除了vector外,这里也可以用set,

multiset.

Limit限定

使用容量可以非常方便的批处理数据,但如果数据库中的数据量巨大时,也将存在一定风险,可能会导致应用程序很少时间才得到响应。另外,你也可能需要更细粒度的控制你的查询,比如你只想获取一个子集的数据。

为解决此问题,我们可以使用limit限定。

假设我们查询了几千行数据到一个用户界面,为便于用户操作,我们可以将此数据进行分隔:

std::vector names;

ses << "SELECT NAME FROM

FORENAME", into(names), limit(50), now;

以上代码将只返回50行的数据。(当然也可能什么都不返回),并追加到

names这个容量中。如果想确保50行记录返回,需要设置limit的第二参数为true(默认为false):

std::vector names;

ses << "SELECT NAME FROM

FORENAME", into(names), limit(50, true), now;

当statement.donw()返回true后,通过statement返回的数据集将是完整的,并可用来遍历。在以下的例子中,我们假设数据库中有101行记录:

std::vector names;

Statement stmt = (ses <<

"SELECT NAME FROM FORENAME", into(names),

limit(50));

stmt.execute(); //names.size()

== 50

poco_assert

(!stmt.done());

stmt.execute(); //names.size()

== 100

poco_assert

(!stmt.done());

stmt.execute(); //names.size()

== 101

poco_assert

(stmt.done());

前面我们指出,如果没有数据返回的话,以上用法也是有效的。因此,在一个空的数据表中,执行以下语句是正常的:

std::string aName;

ses << "SELECT NAME FROM

FORENAME", into(aName), now;

为保证至少返回一个有效的数据,可使用lowerLimit语句:

std::string aName;

ses << "SELECT NAME FROM

FORENAME", into(aName), lowerLimit(1), now;

如果数据表为空的话,以上语句将抛出一个异常。如果查询正常,aName将被正确的初始化。注意,limit只是upperLimit的简写。如需单条遍历结果集,比如某个不想用容器,那么可以这样写:

std::string aName;

Statement stmt = (ses <<

"SELECT NAME FROM FORENAME", into(aName), lowerLimit(1),

upperLimit(1));

while

(!stmt.done())

stmt.execute();

还有一个更简便的方法,就是用range指令:

std::string aName;

Statement stmt = (ses <<

"SELECT NAME FROM FORENAME", into(aName), range(1,1));

while

(!stmt.done())

stmt.execute();

range还有第三个可选参数是boolean类型,用于指定upper

limit是否是强行限定,默认是false.

复合数据类型的映射

前面的例子,我们都是使用基本数据类型(整型,字符串)。现实中的场景可能不太一样,比如我们有一个Person的类:

class Person

{

public:

// default constructor+destr.

// getter and setter methods for all

members

[...]

bool operator

const

/// we

need this for set and multiset support

{

return

_socialSecNr < p._socialSecNr;

}

Poco::UInt64 operator()() const

/// we

need this operator to return the key for the map and

multimap

{

return

_socialSecNr;

}

private:

std::string _firstName;

std::string _lastName;

Poco::UInt64 _socialSecNr;

}

理想情况下,我们希望像字符串一样的使用Person类。为此,你需要创建一个TypeHandler的模板类。注意,此模板的声明必须与原始模板在同一个命令空间,比如Poco:Data.

此模板声明需实现以下方法:

namespace Poco {

namespace Data {

template <>

class TypeHandler

{

public:

static std::size_t size()

{

return 3;

// we handle three columns of the Table!

}

static void bind(std::size_t pos, const

Person& obj, AbstractBinder* pBinder)

{

poco_assert_dbg (pBinder != 0);

// the

table is defined as Person (FirstName VARCHAR(30), lastName

VARCHAR, SocialSecNr INTEGER(3))

// Note

that we advance pos by the number of columns the datatype uses! For

string/int this is one.

TypeHandler::bind(pos++, obj.getFirstName(), pBinder);

TypeHandler::bind(pos++, obj.getLastName(), pBinder);

TypeHandler::bind(pos++, obj.getSocialSecNr(),

pBinder);

}

static void prepare(std::size_t pos, const

Person& obj, AbstractPreparation* pPrepare)

{

poco_assert_dbg (pBinder != 0);

// the

table is defined as Person (FirstName VARCHAR(30), lastName

VARCHAR, SocialSecNr INTEGER(3))

// Note

that we advance pos by the number of columns the datatype uses! For

string/int this is one.

TypeHandler::prepare(pos++, obj.getFirstName(),

pPrepare);

TypeHandler::prepare(pos++, obj.getLastName(),

pPrepare);

TypeHandler::prepare(pos++, obj.getSocialSecNr(),

pPrepare);

}

static void extract(std::size_t pos, Person&

obj, const Person& defVal, AbstractExtractor*

pExt)

/// obj

will contain the result, defVal contains values we should use when

one column is NULL

{

poco_assert_dbg (pExt != 0);

std::string firstName;

std::string lastName;

Poco::UInt64 socialSecNr = 0;

TypeHandler::extract(pos++, firstName, defVal.getFirstName(),

pExt);

TypeHandler::extract(pos++, lastName, defVal.getLastName(),

pExt);

TypeHandler::extract(pos++, socialSecNr, defVal.getSocialSecNr(),

pExt);

obj.setFirstName(firstName);

obj.setLastName(lastName);

obj.setSocialSecNr(socialSecNr);

}

};

} } // namespace

Poco::Data

之后,你就可以把Person类与字符串一样的使用:

std::map people;

ses << "SELECT * FROM

Person", into(people), now;

你可能感兴趣的:(poco,mysql,中文)