如果我翻译错了或者翻译的不好,欢迎指正~

Developing Database Applications Using MySQL Connector/C++

这个教程会教你搭建安装MySQL Connector/C++ driver的要点和步骤,以一个简单的连接MySQL的例子,从MySQL中获取数据并对其进行插入(数据)操作。因为重点在于从C++程序连接数据库,所以本文档假设MySQL已经运行并且能从客户端访问。

本文是面向那些初次接触MySQL Connector/C++的程序开发者的教程,并不是讲述C++编程和MySQL数据库的。

构建和运行本教程的例子需要下列工具和技术来编译:

Database

MySQL Server 5.1.24-rc

C++ Driver

MySQL Connector/C++ 1.0.5

MySQL Client Library

MySQL Connector/C 6.0

Compiler

Sun Studio 12 C++ compiler

Make

CMake 2.6.3

Operating System

OpenSolaris 2008.11 32-bit

CPU / ISA

Intel Centrino / x86

Hardware

Toshiba Tecra M2 Laptop

CONTENTS

MySQL C++ Driver 基于JDBC 4.0标准实现

MySQL Connector/C++是最新发布的MySQL连接器,由Sun Microsystems开发。MySQL connector为C++提供面向对象的编程接口(API)和连接MySQL Server的数据库驱动器

与现存的driver不同,Connector/C++是JDBC API在C++中的实现。换句话说,Connector/C++ driver的接口主要是基于Java语言的JDBC API。Java数据库连接(JDBC)是Java连接各种数据库的业界标准。Connector/C++实现了JDBC 4.0的大部分规范。熟悉JDBC编程的C++程序开发者可以提高程序开发的效率。

MySQL Connecotr/C++实现了以下类:

Driver

Connection

Statement

PreparedStatement

ResultSet

Savepoint

DatabaseMetaData

ResultSetMetaData

ParameterMetaData

Connecotr/C++ driver可用于连接MySQL5.1以及后续版本。

在MySQL Connector/C++出现之前,C++程序员需要使用非标准的、过程化的MySQL C API或MySQL++ API连接MySQL,MySQL Connector/C++是MySQL C API的C++封装

安装MySQL Connector/C++

从二进制程序安装

从1.0.4版本开始,Connector/C++可用于Solaris, Linux, Windows, FreeBSD, Mac OS X, HP-UX and AIX平台。MSI安装程序和二进制ZIP文件并不需要安装程序可用于Windows,GNU TAR的压缩文档(tar.gz)可用于其他的平台。你可以从“Connector/C++ download“下载预编译的二进制文件。

在Windows和其他平台下二进制包的安装是非常简单的-简单的解压缩文档到指定位置安装Connector/C++ driver。静态链接和动态链接的Connector/C++ driver可以在安装目录下找到lib目录。如果您打算使用动态链接版本的MySQL连接器/ C + +,要确保运行时链接程序可以找到MySQL客户端库。请查阅你操作系统文档,修改和扩展库的搜索路径。如果你无法修改库的搜索路径,那么复制你的程序、MySQL Connector/C++ driver和MySQL客户端库到相同的目录。这种方法在大多数平台都可行,编译器到其他地方都所必须动态库之前会先搜索原始目录(当前目录)。

从源码安装

运行时依赖

略(英语水平有限,这一段翻译的不通畅,就不写了,于阅读本教程没什么影响)

使用IDE开发C++程序

如果你正在寻找一个集成开发环境(IDE)来开发C/C++程序,可以考虑使用开源免费的NetBeans平台。NetBeans C/C++开发包让程序员可以使用他们指定的编译器和工具来搭配NetBeans IDE,构建Solaris,Linux,Windows和Mac OS X的原生应用。C/C++开发包使编辑器具有语言识别功能,可以识别C/C++语言,并且提供项目模板,一个动态类浏览器,支持Makefile和m(不知道是什么)调试器功能。可以通过模块和插件来扩展C/C++开发包的基础功能。

为实例代码创建City表和test数据库

本教程中的简单示例代码尝试获取MySQL中的test数据库中的City表的数据。此表的结构和数据已经使用mysql客户端显示在下面。MySQL服务运行在3306默认端口。

# mysql -u root -p

Enter password: admin

Welcome to the MySQL monitor. Commands end with ; or \g.

Your MySQL connection id is 5

Server version: 5.1.24-rc-standard Source distribution

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> USE test;

Database changed

mysql> DESCRIBE City;

+----------+-------------+------+-----+---------+-------+

| Field | Type | Null | Key | Default | Extra |

+----------+-------------+------+-----+---------+-------+

| CityName | varchar(30) | YES | | NULL | |

+----------+-------------+------+-----+---------+-------+

1 row in set (0.07 sec)

mysql> SHOW CREATE TABLE City\G

*************************** 1. row ***************************

Table: City

Create Table: CREATE TABLE `City` (

`CityName` varchar(30) DEFAULT NULL

) ENGINE=InnoDB DEFAULT CHARSET=ascii

1 row in set (0.00 sec)

mysql> SELECT * FROM City;

+--------------------+

| CityName |

+--------------------+

| Hyderabad, India |

| San Francisco, USA |

| Sydney, Australia |

+--------------------+

3 rows in set (0.17 sec)

本教程的所有例子的运行结果都是使用bash shell显示

使用Connector/C++测试与数据库连接

下面的C++示例代码简单演示如何使用MySQL Connector/C++连接本机的MySQL服务。实例代码使用Connector/C++提供的类似于JDBC的API连接到MySQL中的test数据库,实行一条查询语句,从City表中获取所有行数据,从结果集中提取数据并显示在标准输出上,使用"Prepared Statements"插入几行数据到City表中。

示例代码仅仅供参考。不建议读者使用特定的编码风格。为了简单起见,实例代码假设用户提供了合法的输入,所以下面例子中并没有明确的错误检测代码。

# cat MySQLConnectorC++Client.cpp/*Standard C++ headers*/#include#include#include#include#include

/*MySQL Connector/C++ specific headers*/#include#include#include#include#include#include#include#include#include

#define DBHOST "tcp://127.0.0.1:3306"

#define USER "root"

#define PASSWORD "admin"

#define DATABASE "test"

#define NUMOFFSET 100

#define COLNAME 200

using namespacestd;using namespacesql;static void retrieve_data_and_print (ResultSet *rs, int type, int colidx, stringcolname) {/*retrieve the row count in the result set*/cout<< "\nRetrieved" << rs -> rowsCount() << "row(s)." <

cout<< "\nCityName" <

cout<< "--------" <

while (rs->next()) {if (type ==NUMOFFSET) {

cout<< rs -> getString(colidx) <

}else if (type ==COLNAME) {

cout<< rs -> getString(colname) <

}//if-else

} //while

cout<

}//retrieve_data_and_print()

static void retrieve_dbmetadata_and_print (Connection *dbcon) {if (dbcon ->isClosed()) {throw runtime_error("DatabaseMetaData FAILURE - database connection closed");

}

cout<< "\nDatabase Metadata" <

cout<< "-----------------" <

cout<

//auto_ptr < DatabaseMetaData > dbcon_meta (dbcon -> getMetaData());

DatabaseMetaData*dbcon_meta = dbcon ->getMetaData();

cout<< "Database Product Name:" << dbcon_meta -> getDatabaseProductName() <

cout<< "Database Product Version:" << dbcon_meta -> getDatabaseProductVersion() <

cout<< "Database User Name:" << dbcon_meta -> getUserName() << endl <

cout<< "Driver name:" << dbcon_meta -> getDriverName() <

cout<< "Driver version:" << dbcon_meta -> getDriverVersion() << endl <

cout<< "Database in Read-Only Mode?:" << dbcon_meta -> isReadOnly() <

cout<< "Supports Transactions?:" << dbcon_meta -> supportsTransactions() <

cout<< "Supports DML Transactions only?:" << dbcon_meta -> supportsDataManipulationTransactionsOnly() <

cout<< "Supports Batch Updates?:" << dbcon_meta -> supportsBatchUpdates() <

cout<< "Supports Outer Joins?:" << dbcon_meta -> supportsOuterJoins() <

cout<< "Supports Multiple Transactions?:" << dbcon_meta -> supportsMultipleTransactions() <

cout<< "Supports Named Parameters?:" << dbcon_meta -> supportsNamedParameters() <

cout<< "Supports Statement Pooling?:" << dbcon_meta -> supportsStatementPooling() <

cout<< "Supports Stored Procedures?:" << dbcon_meta -> supportsStoredProcedures() <

cout<< "Supports Union?:" << dbcon_meta -> supportsUnion() << endl <

cout<< "Maximum Connections:" << dbcon_meta -> getMaxConnections() <

cout<< "Maximum Columns per Table:" << dbcon_meta -> getMaxColumnsInTable() <

cout<< "Maximum Columns per Index:" << dbcon_meta -> getMaxColumnsInIndex() <

cout<< "Maximum Row Size per Table:" << dbcon_meta -> getMaxRowSize() << "bytes" <

cout<< "\nDatabase schemas:" <

auto_ptr< ResultSet > rs ( dbcon_meta ->getSchemas());

cout<< "\nTotal number of schemas =" << rs -> rowsCount() <

cout<next()) {

cout<< "\t" << row << "." << rs -> getString("TABLE_SCHEM") <

}//while

cout<< endl <

}//retrieve_dbmetadata_and_print()

static void retrieve_rsmetadata_and_print (ResultSet *rs) {if (rs -> rowsCount() == 0) {throw runtime_error("ResultSetMetaData FAILURE - no records in the result set");

}

cout<< "ResultSet Metadata" <

cout<< "------------------" <

//auto_ptr < ResultSetMetaData > res_meta ( rs -> getMetaData() );

ResultSetMetaData*res_meta = rs ->getMetaData();int numcols = res_meta ->getColumnCount();

cout<< "\nNumber of columns in the result set =" << numcols << endl <

cout.width(20);

cout<< "Column Name/Label";

cout.width(20);

cout<< "Column Type";

cout.width(20);

cout<< "Column Size" <

cout.width(20);

cout<< res_meta -> getColumnLabel (i+1);

cout.width(20);

cout<< res_meta -> getColumnTypeName (i+1);

cout.width(20);

cout<< res_meta -> getColumnDisplaySize (i+1) << endl <

}

cout<< "\nColumn \"" << res_meta -> getColumnLabel(1);

cout<< "\" belongs to the Table: \"" << res_meta -> getTableName(1);

cout<< "\" which belongs to the Schema: \"" << res_meta -> getSchemaName(1) << "\"" << endl <

}//retrieve_rsmetadata_and_print()

int main(int argc, const char *argv[]) {

Driver*driver;

Connection*con;

Statement*stmt;

ResultSet*res;

PreparedStatement*prep_stmt;

Savepoint*savept;int updatecount = 0;/*initiate url, user, password and database variables*/

string url(argc >= 2 ? argv[1] : DBHOST);const string user(argc >= 3 ? argv[2] : USER);const string password(argc >= 4 ? argv[3] : PASSWORD);const string database(argc >= 5 ? argv[4] : DATABASE);try{

driver=get_driver_instance();/*create a database connection using the Driver*/con= driver ->connect(url, user, password);/*alternate syntax using auto_ptr to create the db connection*/

//auto_ptr con (driver -> connect(url, user, password));

/*turn off the autocommit*/con-> setAutoCommit(0);

cout<< "\nDatabase connection\'s autocommit mode =" << con -> getAutoCommit() <setSchema(database);/*retrieve and display the database metadata*/retrieve_dbmetadata_and_print (con);/*create a statement object*/stmt= con ->createStatement();

cout<< "Executing the Query: \"SELECT * FROM City\" .." < executeQuery ("SELECT * FROM City");

cout<< "Retrieving the result set .." <

cout<< "Demonstrating Prepared Statements .." << endl < prepareStatement ("INSERT INTO City (CityName) VALUES (?)");

cout<< "\tInserting \"London, UK\" into the table, City .." <

prep_stmt-> setString (1, "London, UK");

updatecount= prep_stmt ->executeUpdate();

cout<< "\tCreating a save point \"SAVEPT1\" .." <

savept= con -> setSavepoint ("SAVEPT1");

cout<< "\tInserting \"Paris, France\" into the table, City .." <

prep_stmt-> setString (1, "Paris, France");

updatecount= prep_stmt ->executeUpdate();

cout<< "\tRolling back until the last save point \"SAVEPT1\" .." <

con->rollback (savept);

con->releaseSavepoint (savept);

cout<< "\tCommitting outstanding updates to the database .." <

con->commit();

cout<< "\nQuerying the City table again .." <

res= stmt -> executeQuery ("SELECT * FROM City");/*retrieve the data from the result set and display on stdout*/retrieve_data_and_print (res, COLNAME,1, string ("CityName"));

cout<< "Cleaning up the resources .." <

delete stmt;

delete prep_stmt;

con->close();

delete con;

}catch (SQLException &e) {

cout<< "ERROR: SQLException in" <<__file__>

cout<< "(" << __func__<< ") on line" << __LINE__ <

cout<< "ERROR:" <

cout<< "(MySQL error code:" <

cout<< ", SQLState:" << e.getSQLState() << ")" <

Message: Unknown command*/cout<< "\nYour server does not seem to support Prepared Statements at all.";

cout<< "Perhaps MYSQL < 4.1?" <

}returnEXIT_FAILURE;

}catch (std::runtime_error &e) {

cout<< "ERROR: runtime_error in" <<__file__>

cout<< "(" << __func__ << ") on line" << __LINE__ <

cout<< "ERROR:" << e.what() <

}returnEXIT_SUCCESS;

}//main()

# CC -V

CC: Sun C++ 5.9 SunOS_i386 Patch 124864-09 2008/12/16# CC-o mysqlconnectorc++client -g0 -xO4 -features=extensions -I/opt/coolstack/mysql_32bit/include/mysql \-I/export/expts/MySQLConnectorC++/include/cppconn -L/opt/coolstack/mysql_32bit/lib/mysql \-L/export/expts/MySQLConnectorC++/lib -lmysqlclient_r -lmysqlcppconn MySQLConnectorC++Client.cpp# export LD_LIBRARY_PATH=/opt/coolstack/mysql_32bit/lib/mysql:/export/expts/ConnectorC++/lib/:$LD_LIBRARY_PATH

# ./mysqlconnectorc++client localhost root admin test

Database connection's autocommit mode = 0

Database Metadata-----------------Database Product Name: MySQL

Database Product Version:5.1.24-rc-standard

Database User Name: root@localhost

Driver name: MySQL Connector/C++Driver version:1.0.5Databasein Read-Only Mode?: falseSupports Transactions?: trueSupports DML Transactions only?: falseSupports Batch Updates?: trueSupports Outer Joins?: trueSupports Multiple Transactions?: trueSupports Named Parameters?: falseSupports Statement Pooling?: falseSupports Stored Procedures?: trueSupports Union?: trueMaximum Connections:151Maximum Columns per Table:512Maximum Columns per Index:16Maximum Row Size per Table:2147483639bytes

Database schemas:

Total number of schemas= 4

1. information_schema2. ISVe3. mysql4. test

Executing the Query:"SELECT * FROM City"..

Retrieving the result set ..

Retrieved3row(s).

CityName--------Hyderabad, India

San Francisco, USA

Sydney, Australia

ResultSet Metadata------------------Number of columnsin the result set = 1Column Name/Label Column Type Column Size

CityName VARCHAR30Column"CityName" belongs to the Table: "City" which belongs to the Schema: "test"Demonstrating Prepared Statements ..

Inserting"London, UK"into the table, City ..

Creating a save point"SAVEPT1"..

Inserting"Paris, France"into the table, City ..

Rolling backuntil the last save point "SAVEPT1"..

Committing outstanding updates to the database ..

Querying the City table again ..

Retrieved4row(s).

CityName--------Hyderabad, India

San Francisco, USA

Sydney, Australia

London, UK

Cleaning up the resources ..

上述示例代码的一些重要步骤说明如下:

建立一个连接到MySQL Server

通过sql::Driver对象实例的sql::Connection成员与MySQL建立连接,sql::Driver对象通过sql::Driver::get_driver_instance函数的返回值设定,而sql::Driver::connect函数返回一个sql::Connection对象。

注:

上一段使用的::::符号为完全限定的函数名。例如,在sql::Driver::get_driver_instance()中,sql是名称空间,Driver是类名以及get_driver_instance()是函数名。在C++程序中如此使用Connector/C++,你可以在代码头中使用"using namespace sql;"指令,这样每次使用相应声明的时候就不需要用“sql::”前缀。所以本教程其余部分使用“sql”名称空间中的函数或其他成员时,都省略了“sql”名称空间的前缀,这样会更简单清晰。

下面是Driver::get_driver_instance和Driver::connect函数的签名。你可以通过查看安装程序中的driver.h头文件获取完整的函数列表。

/*driver.h*/Driver*Driver::get_driver_instance()

Connection* Driver::connect(const std::string& URL, const std::string& userName, const std::string&password)

Connection* Driver::connect(std::map<:string connectpropertyval> properties)

connect在Driver类中是一个重载函数。这里有两个重载版本。在第一个版本中,connect接受一个数据库连接URL以及数据库的用户名和密码。第二个版本中,connector接受一个std::map对象,此对象是包含了数据库连接的URL,用户名和密码的键值对。

你可以在连接URL中指定TCP/IP,“tcp://[hostname[:port]][/schemaname]"的形式连接到MySQL。例如:tcp://127.0.0.1:5555/some_schema. hostname和port是可选的,默认使用127.0.0.1和3306.运行时,"localhost"会自动转换成127.0.0.1。是否指定schema name 也是可选的,如果没设置,则必须使用Connector::setSchema函数来设置schema。

如果你要使用UNIX域的套接口来连接本机的MySQL Server,需在数据库连接URL中指定"unix://path/to/unix_socket_file"。例如:unix://tmp/mysql.sock. 在Windwos中,你可以使用命名管道来连接MySQL Server,需要在数据库连接URL中指定字符串"pipe://path/to/the/pipe"。要启用管道支持,必须在启动MySQL时加上--enable-named-pipe选项。如果你没有使用--socket=name选项指定管道名称,那么会默认创建名为MySQL的命名管道。在Microsoft Windows中,name不区分大小写。

下列代码尝试连接到本地的MySQL Server默认端口:3306,使用root用户名,密码为admin,schema名称为test.

using namespacesql;

Driver*driver;

Connection*con;try{

driver=get_driver_instance();

con= driver -> connect("tcp://127.0.0.1:3306/test", "root", "admin");

}catch(..) {

..

}

connect也可以像下面这样使用,调用第二个重载版本。ConnectPropertyVal是一个枚举类型,定义在connection.h头文件中。编译此段代码需要包含map头文件。

..

std::map conn_properties;

ConnectPropertyVal tmp;

tmp.str.val= "unix:///tmp/mysql.sock";

conn_properties [std::string("hostName")] =tmp;

tmp.str.val= "root";

conn_properties [std::string("userName")] =tmp;

tmp.str.val= "admin";

conn_properties [std::string("password")] =tmp;try{

driver=get_driver_instance();

con= driver ->connect(conn_properties);

}catch(..) {

..

}

如果你更喜欢使用指定UNIX套接口协议,可以重写上述代码的数据库连接URL,如下所示:

tmp.str.val = "unix://" "/tmp/mysql.sock";

一旦建立了连接,你就可以使用Connection::setSessionVariable函数来设置变量,如sql_mode。

C++ Specific Note

"sql::Connection *con = driver -> connect("tcp://127.0.0.1:3306", "root", "admin");”语句可以使用auto_ptr来重写:

std::auto_ptr < sql::Connection > con ( driver -> connect("tcp://127.0.0.1:3306", "root", "admin") );

= OR =

use namespace std;

use namespace sql;

auto_ptr < Connection > con ( driver -> connect("tcp://127.0.0.1:3306", "root", "admin") );

C++标准模板类auto_ptr帮助开发者管理动态内存分配,防止在意想不到的情况下发生内存泄漏,比如在某些情况下,正常的清理(内存)代码被跳过了。auto_ptr对象与指针具有相同的语义,但是auto_ptr对象超出作用域时将会自动释放掉动态分配的内存。也就是说,使用auto_ptr时,你不必显式使用delete操作符来释放内存,delete con;

要使用auto_ptr类,你需要包含这个头文件,并且auto_ptr是定义在std名称空间内的,所以也要通过std名称空间来访问。type可以是指向任意类型/对象的指针。

至于采用auto_ptr智能指针机制,还是传统机制来动态管理内存,由读者自己决定。

获取一个Statement对象

当调用Connection::createStatement函数时,返回一个Statement对象,它可以用来向数据库服务器发送SQL语句。一般情况下,Statement对象执行的是不带参数的SQL语句。换句话说,一个Statement对象用于执行静态SQL语句,并返回其执行结果。如果需要执行多次不同输入的SQL语句,可以考虑使用Prepared Statements对象。

Connection::createStatement的函数签名(原型)如下所示,完整的Connection的接口函数列表,请阅看你的Connector/C++安装文件中的connection.h头文件

/*connection.h*/Statement* Connection::createStatement();

下面代码片段调用Connection对象中的createStatement函数,获得一个Statement类型的对象。

Connection *con;

Statement*stmt;

Statement stmt= con -> createStatement();

这个例子中,con是Connection类型的引用(指针)

执行SQL语句

在执行SQL语句前,你需要先连接数据库,并且选择相应的数据库架构。通过调用Connection对象中的setSchema函数来选择需要连接的架构,setSchema函数的参数是架构的名称。

以SQL语句作为(executeQuery的)参数,调用Statement::executeQuery函数执行查询语句。executeQuery()返回一个ResultSet对象。Statement::executeUpdate函数可用于执行特定的SQL语句,如INSERT,UPDATE,DELETE。或者是不返回任何结果的SQL语句,如SQL DDL语句。与excuteQuery()不同,excuteUpdate函数不返回ResultSet对象。相反,它返回INSERT,UPDATE,DELETE操作后受影响的行数。

如果你事先并不知道SQL语句是SELECT还是INSERT,UPDATE或DELETE,你可以使用execute函数。当SQL语句是SELECT操作时,execute()返回true,当SQL语句是INSERT,UPDATE,DELETE操作时,execute()返回false。如果语句是SELECT查询操作,你可以调用Statement实例中的getResultSet函数获取查询结果集。如果语句是INSERT,UPDATE,DELETE操作,你可以调用getUpdateCount()获取受影响的行数。

在少数情况下,一条SQL语句可能返回多个结果和/或更新行数。一般情况下,你可以忽略这一点。除非你执行一个存储过程,你知道可能会返回多个结果;或者动态执行未知的SQL语句。使用getResultSet或getUpdateCount函数可以获取结果,getMoreResults()可以检查是否还有其他结果集合。

相应的函数签名如下所示。完整的Connection和Statement的接口函数列表,请查看connection.h头文件。

/*connection.h*/

void Connection::setSchema(const std::string&catalog);/*statement.h*/ResultSet* Statement::executeQuery (const std::string&sql);int Statement::executeUpdate (const std::string&sql);bool Statement::execute (const std::string&sql);

ResultSet*Statement::getResultSet();

uint64_t Statement::getUpdateCount();

上述所有函数都可能抛出SQLException(SQL异常),所以在代码中必须确保catch(捕捉)到这些异常。为了简单起见,在实例代码中并没有使用try...catch块(指retrieve_data_and_print函数中)。如果你重新查看完整的实例代码,你会发现其目的只是获取test数据库中City表的所有行数据。于是,使用executeQuery()的示例代码如下所示:

Statement *stmt;

ResultSet*res;

res= stmt -> executeQuery ("SELECT * FROM City");

executeQuery函数返回一个ResultSet对象,它包含了给定查询语句所生成的结果数据。当发生数据库访问错误,或调用已关闭的Statement对象,或给定的SQL语句产生的数据超过单一ResultSet对象,executeQuery将抛出SQLException。

另外,上述代码段可以用Statement::execute()重写,如下所示:

bool retvalue = stmt -> execute ("SELECT * FROM City");if(retvalue) {

res= stmt ->getResultSet();

}else{

...

}

如果查询结果是一个ResultSet对象(SELECT操作),execute函数返回true,如果查询结果是更新的行数(UPDATE,INSERT,DELETE)或者无结果,execute函数返回false。如果execute()返回true,使用getResultSet函数可以获取结果集。如果查询结果是更新的行数或者没有结果,getResultSet返回NULL。

execute和getResultSet这两个函数在发生数据库访问错误或在已经关闭的Statement上调用时,都会抛出SQLException.如果你需要插入新记录到数据库,你可以使用executeUpdate函数,如下所示:

int updateCount = stmt -> executeUpdate ("INSERT INTO City (CityName) VALUES ('Napier, New Zealand')");

executeUpdate执行给定的SQL数据操作语言(DML)语句,例如INSERT,UPDATE,DELETE;或不返回任何数据的SQL语句,例如DDL语句。执行INSERT,UPDATE,DELETE操作,executeUpdate()返回受影响的行数,如果SQL语句不返回任何数据,executeUpdate()返回0值。

当发生数据库访问错误或在已关闭的Statement对象上调用executeUpdate(),或者是SQL语句产生一个结果集对象,executeUpdate都会抛出SQLException.

另一方面,使用execute和getUpdateCount函数可以重写上述代码段,如下所示:

int updateCount = 0;bool retstatus = stmt -> execute ("INSERT INTO City (CityName) VALUES ('Napier, New Zealand')");if (!retstatus) {

updateCount= stmt ->getUpdateCount();

}else{

...

}

如果SQL语句的执行的返回结果是受(更新)影响的行数,execute函数返回false,此时可以使用getUpdateCount函数获得受影响行数值。如果SQL语句执行结果返回一个ResultSet对象或者更多结果,getUpdateCount()返回-1.

在已关闭的Statement对象上调用execute和getUpdateCount或出现数据库访问错误的情况下都会抛出SQLException.

从结果集中获取数据

前面的段落解析到,executeQuery和execute两个函数执行SQL查询语句,前者返回一个ResultSet实例。你可以使用ResultSet对象访问SQL查询语句从数据库返回的数据。没一个ResultSet维护一个游标(指针),它指向其当前数据行。利用游标可以顺序读取数据集中的行。在一行中,列的值可以以任意顺序访问。你可以根据列的位置(offset)或它们的列名/标签来访问,后者具有一定的容错性,尤其是在表的架构发生改变后。使用列标签或列名会使代码更加清晰。另一方面,通过列的索引或位置访问,可以提高性能。

列标签就是SQL“AS”子句中指定的标签名。如果SQL“AS”子句没有指定标签,那么标签名就是列名。例如在“SELECT CityName AS CN FROM City”中,CN就是列标签名。

存储在ResultSet中的数据可以通过getXXX函数来获取,例如getString() 或 getInt(),根据数据类型的不同使用相应的函数获取数据。使用使用ResulSet的next和previous函数移动游标指向下一行数据。

ResultSet会一直保持打开,即使生成他的Statement对象关闭了,重新执行可以获取多个结果集队列中的下一个结果。一旦Statement生成了结果集,该ResultSet会一直有效,直到显示或隐式的关闭它(才会失效),不论产生它的Statement对象状态如何,都不会影响到已经产生的ResultSet。

截至撰写这篇文章时,MySQL Connector/C++的Statement对象返回一个结果缓冲区。缓冲区缓存在客户端上。不论结果集多大,driver都会获取所有的数据。connector未来的版本Statement对象有望返回缓冲和非缓冲结果集。

相关的函数签名如下所示。ResultSet支持的接口完整列表请查看resultset.h头文件。

/* resultset.h */

size_t ResultSet::rowsCount() const;

void ResultSet::close();

bool ResultSet::next();

bool ResultSet::previous();

bool ResultSet::last();

bool ResultSet::first();

void ResultSet::afterLast();

void ResultSet::beforeFirst();

bool ResultSet::isAfterLast() const;

bool ResultSet::isBeforeFirst()const;

bool ResultSet::isClosed() const;

bool ResultSet::isNull(uint32_t columnIndex) const;

bool ResultSet::isNull(const std::string& columnLabel) const;

bool ResultSet::wasNull() const;

std::string ResultSet::getString(uint32_t columnIndex) const;

std::string ResultSet::getString(const std::string& columnLabel) const;

int32_t ResultSet::getInt(uint32_t columnIndex) const;

int32_t ResultSet::getInt(const std::string& columnLabel) const;

在实例代码中,语句“SELECT * FROM City”返回的结果集只有一列CityName数据,数据类型为String,在MySQL中为VARCHAR类型

下列代码片段遍历ResultSet对象res,通过准确的列名获取每一行数据,并显示在标准输出上。

while (res ->next()) {

cout<< rs -> getString("CityName") <

}

因为也可以通过列的索引访问,所以下列代码片段也能得到相同的效果:

while (res ->next()) {

cout<< rs -> getString(1) <

}

getString()的整形参数引用查询语句中指定的列,列号从1开始。(译者注:比如“SELECT COLUMN1 COLUMN2 COLUMN3 FROM TABLE”返回的结果中,第一列就是COLUMN1,第二列为COLUMN2,第三列为COLUMN3,通过getString(1)、getString(2)、getString(3)获取对应数据)

这两个版本的getString()都返回列值。如果列值为空(NULL),则返回值为空字符串(string对象)。你可以通过ResultSet::isNull函数,以列索引或列名/列标签作为参数,检查相应的列值是否为SQL NULL。通过ResultSet::wasNull()函数可以确定读取的最后一列的值是否为SQL NULL,此函数没有参数。

下列实例演示如何反向遍历结果集中的数据:

/*Move the cursor to the end of the ResultSet object, just after the last row*/res->afterLast();if (!res ->isAfterLast()) {throw runtime_error("Error: Cursor position should be at the end of the result set after the last row.");

}/*fetch the data : retrieve all the rows in the result set*/

while (res ->previous()) {

cout<< rs -> getString("CityName") <

}

如果列名/列标签无效,或出现数据库访问错误,或在已关闭的ResultSet对象上调用getString(),getString()都会抛出SQLException.

(未完待续)

mysql connector cpp_MySQL Connector/C++(一)相关推荐

  1. flink mysql connector_Flink JDBC Connector:Flink 与数据库集成最佳实践

    整理:陈政羽(Flink 社区志愿者) 摘要:Flink 1.11 引入了 CDC,在此基础上, JDBC Connector 也发生比较大的变化,本文由 Apache Flink Contribut ...

  2. mysql connector api_mysql connector c++ 1.1 API初步体验

    mysql connector c++ 1.1 API初步体验 1,常用的头文件 #include #include #include #include #include #include 2,创建连 ...

  3. mysql eager mode_MySQL Connector Net 6.6.5 Entity Framework 显式预加载 Eager Load Bug

    在将原有系统从MSSQL迁移到MySQL时,遇到莫名其妙的问题,经过排除大法反复试验,锁定问题出自MySQL官方出品的Entity组件.又经过网上搜索,发现类似问题存在由来已久 http://bugs ...

  4. java mysql embedded,java-将MySQL Connector / MXJ用于应用程序的优点/缺点/替代品有哪些...

    我最近使用Play Framework和MySQL Connector / MXJ制作了一个有趣的应用程序,以制作一个具有数据库的完全可移植的Web服务器,而与任何当前安装的软件(包括Java)无关. ...

  5. mysql connector j_MySQL Connector/J

    5.1 Developer Guide 1. MysQL为由Java语言编程的客户端程序提供连接:MySQL Connector/J,这是一个实现Java Database Connectivity( ...

  6. MySQL JDBC 客户端(connector 8.x)反序列化漏洞学习

    MySQL JDBC 反序列化漏洞 最早提出应该是BlackHat Europe 2019会议中的一个议题,下图是机翻的截图. JDBC是Java 的 API,它定义了客戶端如何访问数据库.JDBC是 ...

  7. mysql connector安装教程_通过安装MySQL Connector/Net实现VS2017 C#编程连接MySQL数据库-网络教程与技术 -亦是美网络...

    对编程有一定了解的小伙伴都知道,一般情况下使用微软的visual studio进行编程开发都会搭配自家的SQL server.Access数据库,而开发web程序一般情况下PHP搭配MySQL使用,但 ...

  8. MySQL Connector/ODBC 5.2.2 发布

    MySQL Connector/ODBC 5.2.2 发布,这是一个稳定版本,下载地址: http://dev.mysql.com/downloads/connector/odbc/5.2.html ...

  9. Linux MySQL Connector/C++ 编程实例

    本篇文章介绍如何在Linux平台使用Connector/C++ 连接数据库,假定MySQL已经安装完成.如果还没有安装MySQL,请先安装.MySQL版本:8.0.19 目录 1. 安装Connect ...

最新文章

  1. Python基础知识实例讲解
  2. CA knowledge study
  3. 6 交换机-topic类型
  4. android动画送礼物,Android仿直播类app赠送礼物功能
  5. 【OpenGL从入门到精通(七)】OpenGL中的数学
  6. NHibernate 做个小项目来试一下吧 一
  7. 纸白银:交易简便成本低
  8. 搜索框+ 定时器+Bug解决
  9. 《此生未完成》:她说,名利权情,没有一样是不辛苦的
  10. iphone手机如何修改Apple ID密码
  11. 触动精灵--点击函数封装--一些特殊情况的使用--狂暴传奇
  12. 神经网络与深度学习第三周-Planar data classification with one hidden layer
  13. 年货:Python技术知识清单(数据科学)
  14. HC05蓝牙模块 修改密码 返回 ERROR:(1D)解决办法
  15. s19文件反编译成c语言,S19文件反编译器使用说明.ppt
  16. Android AOA协议Android端 流程总结
  17. 马云说:“未来是大数据的时代”
  18. 超好看的个人网页,你还不fork一下?
  19. 开源免费OA教程:移动端工作表单操作条的使用方法
  20. 网御星云防火墙端口映射配置

热门文章

  1. 页面显示pdf_PDF怎样合并?在Mac上合并PDF文件的最佳方法
  2. ASP.NET Core学习——5
  3. java作业——Day0014
  4. 【题解】luoguP2680运输计划
  5. python之求字典最值
  6. Win10 中将网页转换成pdf的简便方法
  7. 软件工程概论个人总结
  8. 完美实现类似QQ的自拍头像、上传头像功能!(Demo 源码)
  9. linux命令详解——tee
  10. poj1182食物链(种类并查集)