转载原文:http://blog.csdn.net/jgood/article/details/5661339

原文地址: http://dev.mysql.com/tech-resources/articles/mysql-connector-cpp.html#trx

翻译: DarkBull(www.darkbull.net)
示例代码:MySqlDemo.7z
译者注:该教程是一篇介绍如何使用C++操作MySQL的入门教程,内容简单易用。我对原文中的一些例子进行了修改,并新添加了部分例子,主要目标是更简单明了的向读者介绍如何操作MySQL数据库。本人也是MySQL的初学者,错误也在所难免,欢迎拍砖!

这篇教程将一步一步引导您如何去构建和安装MySql Connection/C++ Driver,同时提供几个简单的例子来演示如何连接MySQL数据库,如何向MySQL添加、获取数据。本教程关注如何在C++应用程序中操作MySQL,所以首先应该确定MySQL数据库服务已经开启并且在当前机器能够访问到。

本教程面向的读者是MySQL Connector/C++的初学者,如果您对C++语言或者MySQL数据库不是很了解,请参考其他的教程。
教程使用了下面所列的一些工具和技术,来构建、编译、运行例子程序(译者注:这是原文作者使用的环境。笔者使用的环境是:WinXP,MySQL5.1,VS2008, ):
  • DatabaseMySQL Server 5.1.24-rc
  • C++ DriverMySQL Connector/C++ 1.0.5
  • MySQL Client LibraryMySQL Connector/C 6.0
  • CompilerSun Studio 12 C++ compiler
  • MakeCMake 2.6.3
  • Operating SystemOpenSolaris 2008.11 32-bit
  • CPU / ISAIntel Centrino / x86
  • HardwareToshiba Tecra M2 Laptop

目录

MySQL C++ Driver的实现基于JDBC4.0规范
安装MySQL Connector/C++
运行时依赖
C++ IDE

为示例程序创建数据库与数据表

使用Connector/C++测试数据库连接
使用prepared Statements
使用事务
访问Result Set Metadata
访问Database Metadata
通过PreparedStatment对象访问参数元数据

捕获异常

调试/跟踪 MySQL Connector/C++
更多信息

MySQL C++ Driver的实现基于JDBC4.0规范

MySQL Connector/C++是由Sun Microsystems开发的MySQL连接器。它提供了基于OO的编程接口与数据库驱动来操作MySQL服务器。
与许多其他现存的C++接口实现不同,Connector/C++遵循了JDBC规范。也就是说,Connector/C++ Driver的API主要是基于Java语言的JDBC接口。JDBC是java语言与各种数据库连接的标准工业接口。Connector/C++实现了大部分JDBC4.0规范。如果C++程序的开发者很熟悉JDBC编程,将很快的入门。
MySQL Connector/C++实现了下面这些类:
  • Driver
  • Connection
  • Statement
  • PreparedStatement
  • ResultSet
  • Savepoint
  • DatabaseMetaData
  • ResultSetMetaData
  • ParameterMetaData

Connector/C++可用于连接MySQL5.1及其以后版本。

在MySQL Connector/C++发布之前,C++程序员可以使用MySQL C API或者MySQL++访问MySQL。前者是非标准、过程化的C API,后者是对MySQL C API的C++封装。

安装MySQL Connector/C++

此处略。(译者注:用户可以到MySQL的官网[http://dev.mysql.com/downloads/connector/cpp/1.0.html]去下载MySQL Connector/C++的安装程序,或者只下载dll,或者下载源代码自己编译。笔者在Window平台上使用MySQL,下载了mysql-connector-c++-noinstall-1.0.5-win32这个版本用于调试。)

运行时依赖

MySQL Connector/C++ Driver依赖MySQL的客户端库,在MySQL安装目录下的lib/opt/libmysql.dll。如果是通过安装程序来安装MySQL Connector/C++,libmysql会一并安装,如果从官网只下载了dll或源码,在使用时,程序必须链接到libmysql.dll。

C++ IDE

此处略。(译者注:原文作者使用NetBean作为C++的IED。笔者使用VS2008)

为示例程序创建数据库与数据表

(译者注:此节略掉许多不太重要的内容。)在MySQL中创建test数据库,使用下面语句创建数据表:City:

[sql] view plaincopy
  1. Create Table: CREATE TABLE `City` ( `CityName` varchar(30) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=ascii

然后向City表中添加一些数据。最后表的内容为:

mysql> SELECT * FROM City; 
 +--------------------+ 
 | CityName           | 
 +--------------------+ 
 | Hyderabad, India   | 
 | San Francisco, USA |
 | Sydney, Australia  |
 +--------------------+
 3 rows in set (0.17 sec) 

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

下面的代码演示如何使用Connector/C++连接到MySQL服务器:

  • 连接到test数据库;
  • 执行一个查询获取City表中的数据,显示在控制台上; 
  • 使用Prepared Statements向City表插入数据;
  • 使用savepoints演示事务;
  • 获取结果集和数据库的元信息;
例子代码仅仅用于演示,不建议读者在实际开发中使用这种样式的代码。(译者注:例子代码很长,如果看不太明白,没关系,等阅读完全文之后再回过头来看)

[cpp] view plaincopy
  1. #include <iostream>
  2. #include <map>
  3. #include <string>
  4. #include <memory>
  5. #include "mysql_driver.h"
  6. #include "mysql_connection.h"
  7. #include "cppconn/driver.h"
  8. #include "cppconn/statement.h"
  9. #include "cppconn/prepared_statement.h"
  10. #include "cppconn/metadata.h"
  11. #include "cppconn/exception.h"
  12. #define DBHOST "tcp://127.0.0.1:3306"
  13. #define USER "root"
  14. #define PASSWORD "000000"
  15. #define DATABASE "test"
  16. #define NUMOFFSET 100
  17. #define COLNAME 200
  18. using namespace std;
  19. using namespace sql;
  20. #pragma comment(lib, "mysqlcppconn.lib")
  21. void Demo();
  22. int main(int argc, char *argv[])
  23. {
  24. Demo();
  25. return 0;
  26. }
  27. /* 获取数据库信息 */
  28. static void GetDBMetaData(Connection *dbcon)
  29. {
  30. if (dbcon->isClosed())
  31. {
  32. throw runtime_error("DatabaseMetaData FAILURE - database connection closed");
  33. }
  34. cout << "/nDatabase Metadata" << endl;
  35. cout << "-----------------" << endl;
  36. cout << boolalpha;
  37. /* The following commented statement won't work with Connector/C++ 1.0.5 and later */
  38. //auto_ptr < DatabaseMetaData > dbcon_meta (dbcon->getMetaData());
  39. DatabaseMetaData *dbcon_meta = dbcon->getMetaData();
  40. cout << "Database Product Name: " << dbcon_meta->getDatabaseProductName() << endl;
  41. cout << "Database Product Version: " << dbcon_meta->getDatabaseProductVersion() << endl;
  42. cout << "Database User Name: " << dbcon_meta->getUserName() << endl << endl;
  43. cout << "Driver name: " << dbcon_meta->getDriverName() << endl;
  44. cout << "Driver version: " << dbcon_meta->getDriverVersion() << endl << endl;
  45. cout << "Database in Read-Only Mode?: " << dbcon_meta->isReadOnly() << endl;
  46. cout << "Supports Transactions?: " << dbcon_meta->supportsTransactions() << endl;
  47. cout << "Supports DML Transactions only?: " << dbcon_meta->supportsDataManipulationTransactionsOnly() << endl;
  48. cout << "Supports Batch Updates?: " << dbcon_meta->supportsBatchUpdates() << endl;
  49. cout << "Supports Outer Joins?: " << dbcon_meta->supportsOuterJoins() << endl;
  50. cout << "Supports Multiple Transactions?: " << dbcon_meta->supportsMultipleTransactions() << endl;
  51. cout << "Supports Named Parameters?: " << dbcon_meta->supportsNamedParameters() << endl;
  52. cout << "Supports Statement Pooling?: " << dbcon_meta->supportsStatementPooling() << endl;
  53. cout << "Supports Stored Procedures?: " << dbcon_meta->supportsStoredProcedures() << endl;
  54. cout << "Supports Union?: " << dbcon_meta->supportsUnion() << endl << endl;
  55. cout << "Maximum Connections: " << dbcon_meta->getMaxConnections() << endl;
  56. cout << "Maximum Columns per Table: " << dbcon_meta->getMaxColumnsInTable() << endl;
  57. cout << "Maximum Columns per Index: " << dbcon_meta->getMaxColumnsInIndex() << endl;
  58. cout << "Maximum Row Size per Table: " << dbcon_meta->getMaxRowSize() << " bytes" << endl;
  59. cout << "/nDatabase schemas: " << endl;
  60. auto_ptr < ResultSet > rs ( dbcon_meta->getSchemas());
  61. cout << "/nTotal number of schemas = " << rs->rowsCount() << endl;
  62. cout << endl;
  63. int row = 1;
  64. while (rs->next()) {
  65. cout << "/t" << row << ". " << rs->getString("TABLE_SCHEM") << endl;
  66. ++row;
  67. } // while
  68. cout << endl << endl;
  69. }
  70. /* 获取结果集信息 */
  71. static void GetResultDataMetaBata(ResultSet *rs)
  72. {
  73. if (rs -> rowsCount() == 0)
  74. {
  75. throw runtime_error("ResultSetMetaData FAILURE - no records in the result set");
  76. }
  77. cout << "ResultSet Metadata" << endl;
  78. cout << "------------------" << endl;
  79. /* The following commented statement won't work with Connector/C++ 1.0.5 and later */
  80. //auto_ptr < ResultSetMetaData > res_meta ( rs -> getMetaData() );
  81. ResultSetMetaData *res_meta = rs -> getMetaData();
  82. int numcols = res_meta -> getColumnCount();
  83. cout << "/nNumber of columns in the result set = " << numcols << endl << endl;
  84. cout.width(20);
  85. cout << "Column Name/Label";
  86. cout.width(20);
  87. cout << "Column Type";
  88. cout.width(20);
  89. cout << "Column Size" << endl;
  90. for (int i = 0; i < numcols; ++i)
  91. {
  92. cout.width(20);
  93. cout << res_meta -> getColumnLabel (i+1);
  94. cout.width(20);
  95. cout << res_meta -> getColumnTypeName (i+1);
  96. cout.width(20);
  97. cout << res_meta -> getColumnDisplaySize (i+1) << endl << endl;
  98. }
  99. cout << "/nColumn /"" << res_meta -> getColumnLabel(1);
  100. cout << "/" belongs to the Table: /"" << res_meta -> getTableName(1);
  101. cout << "/" which belongs to the Schema: /"" << res_meta -> getSchemaName(1) << "/"" << endl << endl;
  102. }
  103. /* 打印结果集中的数据 */
  104. static void RetrieveDataAndPrint(ResultSet *rs, int type, int colidx, string colname)
  105. {
  106. /* retrieve the row count in the result set */
  107. cout << "/nRetrieved " << rs->rowsCount() << " row(s)." << endl;
  108. cout << "/nCityName" << endl;
  109. cout << "--------" << endl;
  110. /* fetch the data : retrieve all the rows in the result set */
  111. while (rs->next())
  112. {
  113. if (type == NUMOFFSET)
  114. {
  115. cout << rs -> getString(colidx) << endl;
  116. } else if (type == COLNAME)
  117. {
  118. cout << rs -> getString(colname) << endl;
  119. } // if-else
  120. } // while
  121. cout << endl;
  122. }
  123. void Demo()
  124. {
  125. Driver *driver;
  126. Connection *con;
  127. Statement *stmt;
  128. ResultSet *res;
  129. PreparedStatement *prep_stmt;
  130. Savepoint *savept;
  131. int updatecount = 0;
  132. /* initiate url, user, password and database variables */
  133. string url(DBHOST);
  134. const string user(USER);
  135. const string password(PASSWORD);
  136. const string database(DATABASE);
  137. try
  138. {
  139. driver = get_driver_instance();
  140. /* create a database connection using the Driver */
  141. con = driver -> connect(url, user, password);
  142. /* alternate syntax using auto_ptr to create the db connection */
  143. //auto_ptr  con (driver -> connect(url, user, password));
  144. /* turn off the autocommit */
  145. con -> setAutoCommit(0);
  146. cout << "/nDatabase connection/'s autocommit mode = " << con -> getAutoCommit() << endl;
  147. /* select appropriate database schema */
  148. con -> setSchema(database);
  149. /* retrieve and display the database metadata */
  150. GetDBMetaData(con);
  151. /* create a statement object */
  152. stmt = con -> createStatement();
  153. cout << "Executing the Query: /"SELECT * FROM City/" .." << endl;
  154. /* run a query which returns exactly one result set */
  155. res = stmt -> executeQuery ("SELECT * FROM City");
  156. cout << "Retrieving the result set .." << endl;
  157. /* retrieve the data from the result set and display on stdout */
  158. RetrieveDataAndPrint (res, NUMOFFSET, 1, string("CityName"));
  159. /* retrieve and display the result set metadata */
  160. GetResultDataMetaBata (res);
  161. cout << "Demonstrating Prepared Statements .. " << endl << endl;
  162. /* insert couple of rows of data into City table using Prepared Statements */
  163. prep_stmt = con -> prepareStatement ("INSERT INTO City (CityName) VALUES (?)");
  164. cout << "/tInserting /"London, UK/" into the table, City .." << endl;
  165. prep_stmt -> setString (1, "London, UK");
  166. updatecount = prep_stmt -> executeUpdate();
  167. cout << "/tCreating a save point /"SAVEPT1/" .." << endl;
  168. savept = con -> setSavepoint ("SAVEPT1");
  169. cout << "/tInserting /"Paris, France/" into the table, City .." << endl;
  170. prep_stmt -> setString (1, "Paris, France");
  171. updatecount = prep_stmt -> executeUpdate();
  172. cout << "/tRolling back until the last save point /"SAVEPT1/" .." << endl;
  173. con -> rollback (savept);
  174. con -> releaseSavepoint (savept);
  175. cout << "/tCommitting outstanding updates to the database .." << endl;
  176. con -> commit();
  177. cout << "/nQuerying the City table again .." << endl;
  178. /* re-use result set object */
  179. res = NULL;
  180. res = stmt -> executeQuery ("SELECT * FROM City");
  181. /* retrieve the data from the result set and display on stdout */
  182. RetrieveDataAndPrint(res, COLNAME, 1, string ("CityName"));
  183. cout << "Cleaning up the resources .." << endl;
  184. /* Clean up */
  185. delete res;
  186. delete stmt;
  187. delete prep_stmt;
  188. con -> close();
  189. delete con;
  190. } catch (SQLException &e) {
  191. cout << "ERROR: " << e.what();
  192. cout << " (MySQL error code: " << e.getErrorCode();
  193. cout << ", SQLState: " << e.getSQLState() << ")" << endl;
  194. if (e.getErrorCode() == 1047) {
  195. /*
  196. Error: 1047 SQLSTATE: 08S01 (ER_UNKNOWN_COM_ERROR)
  197. Message: Unknown command
  198. */
  199. cout << "/nYour server does not seem to support Prepared Statements at all. ";
  200. cout << "Perhaps MYSQL < 4.1?" << endl;
  201. }
  202. return;
  203. } catch (std::runtime_error &e) {
  204. cout << "ERROR: " << e.what() << endl;
  205. return;
  206. }
  207. return;
  208. }
建立数据库连接

sql::Connection代表到数据库的连接,可以通过sql::Driver来创建。sql::mysql::get_mysql_driver_instance()方法用于获取sql::Driver,通过调用sql::Driver::connect方法来创建sql::Connection对象。(译者注:笔者使用的Connector/C++版本与作者使用的版本不一样,接口方面也有点细微的差别。这里根据笔者使用的最新版本mysql-connector-c++-noinstall-1.0.5-win32来说明。)

下面是get_mysql_driver_instance与connect这两个方法的签名:
[cpp] view plaincopy
  1. /* mysql_driver.h */
  2. MySQL_Driver *sql::mysql::get_mysql_driver_instance()
  3. /* mysql_driver.h */
  4. sql::Connection * connect(const std::string& hostName, const std::string& userName, const std::string& password);
  5. sql::Connection * connect(std::map<std::string, sql::ConnectPropertyVal> & options);
Driver类重载了connect方法,一个接收数据库地址的url、用户名和密码的字符串,后一个接收一个map,map中以key/value的形式包含数据库地址、用户名与密码。使用TCP/IP连接到MySql服务器的url字符串的格式如下:"tcp://[hostname[:port]][/schemaname]"。例如:tcp://127.0.0.1:5555/some_scehma。hostname和端口号是可选的,如果省略,默认是127.0.0.1与3306。如果hostname为"localhost",会被自动转换为"127.0.0.1"。schemaname也是可选的,如果连接字符串中没有设置schema,需要在程序中通过Connection::setSchema方法手动设置。

在unix系统上,可以通过UNIX domain socket连接运行在本地的MySQL服务,连接字符串格式为:"unix://path/to/unix_socket_file",例如:unix:///tmp/mysql.sock.

在windows系统上,可以以命名管道的方式连接到运行在本地的MySQL数据库,连接字符串格式为:"pipe://path/to/the/pipe"。MySQL服务必须启动允许命名管道连接,可以在启动MySQL服务器的时候,通过--enable-named-pipe命令行选项来启动该功能。如果没有通过--socket=name选项设置命名管道的名称,系统默认使用MySQL。在windows上,管道的名称是区别大小写的。
    下面的代码片断尝试连接到本地的MySQL服务器,通过3306端口,用户名为root,密码是000000,schema为test.
[cpp] view plaincopy
  1. sql::mysql::MySQL_Driver *driver = 0;
  2. sql::Connection *conn = 0;
  3. try
  4. {
  5. driver = sql::mysql::get_mysql_driver_instance();
  6. conn = driver->connect("tcp://localhost:3306/test", "root", "000000");
  7. cout << "连接成功" << endl;
  8. }
  9. catch (...)
  10. {
  11. cout << "连接失败" << endl;
  12. }
  13. if (conn != 0)
  14. {
  15. delete conn;
  16. }
也可以通过connection的第二个重载方法连接MySQL。ConnectPropertyVal是union类型,在connection.h中定义。

[cpp] view plaincopy
  1. sql::mysql::MySQL_Driver *driver = 0;
  2. sql::Connection *conn = 0;
  3. std::map<std::string, ConnectPropertyVal> connProperties;
  4. ConnectPropertyVal tmp;
  5. tmp.str.val = "tcp://127.0.0.1:3306/test";
  6. connProperties[std::string("hostName")] = tmp;
  7. tmp.str.val = "root";
  8. connProperties[std::string("userName")] = tmp;
  9. tmp.str.val = "000000";
  10. connProperties[std::string("password")] = tmp;
  11. try
  12. {
  13. driver = sql::mysql::get_mysql_driver_instance();
  14. conn = driver -> connect(connProperties);
  15. cout << "连接成功" << endl;
  16. }
  17. catch(...)
  18. {
  19. cout << "连接失败" << endl;
  20. }
  21. if (conn != 0)
  22. {
  23. delete conn;
  24. }

上面的连接字符串可以将协议与路径分开写(译者注:C++会把两个连在一起的字符串合并成一个字符串),如:mp.str.val = "unix://" "/tmp/mysql.sock"
当建立与服务器之间的连接后,通过Connection::setSessionVariable方法可以设置像sql_mode这样的选项。
C++细节注意点

像Connection这样的对象,必须在用完之后,显式的delete,例如:

[cpp] view plaincopy
  1. sql::Connection *conn = driver -> connect("tcp://127.0.0.1:3306", "root", "000000");
  2. // do something
  3. delete conn

使用使用auto_ptr来维护连接对象的清理, 如:
[cpp] view plaincopy
  1. use namespace std;
  2. use namespace sql;
  3. auto_ptr < Connection > con ( driver -> connect("tcp://127.0.0.1:3306", "root", "000000") );
获取Statement对象
Statement对象用于向MySQL服务器发送SQL语句。该对象可以通过调用Connection::createStatement方法获得。Statement向MySQL发送一个静态的SQL语句,然后从MySQL获取操作的结果,我们无法向它提供sql参数。如果要向它传递参数,可以使用PreparedStatemenet类。如果相同的SQL语句(只SQL参数不同)要被执行多次,建议使用PreparedStatement类。
    Connection::createStatement的签名如下(关于Connection类所提供的方法列表,可以查看connection.h头文件):
[cpp] view plaincopy
  1. /* connection.h */
  2. ment* Connection::createStatement();

下面的的代码段通过调用Connection对象的createStatemenet来获取一个Statement对象:

[cpp] view plaincopy
  1. Connection *conn;  // Connection对象的引用
  2. Statement *stat;
  3. Statement stat = conn -> createStatement();

执行SQL语句
在执行SQL语句之前应该通过Connection对象的setSchema方法设置相应的Schema(如果没有在数据库地址URL中指定schema)。
Statement::executeQuery用于执行一个Select语句,它返回ResultSet对象。Statement::executeUpdate方法主要用于执行INSERT, UPDATE, DELETE语句(executeUpdate可以执行所有的SQL语句,如DDL语句,像创建数据表。),该方法返回受影响记录的条数。
如果你不清楚要执行的是像select这样的查询语句还是像update/insert/delete这样的操作语句,可以使用execute方法。对于查询语句,execute()返回True,然后通过getResultSet方法获取查询的结果;对于操作语句,它返回False,通过getUpdateCount方法获取受影响记录的数量。
在一些特殊的情况下,单条SQL语句(如执行存储过程),可能会返回多个结果集 和/或 受影响的记录数量。如果你不想忽略这些结果,通过getResultSet或getUpdateCount方法第一个结果后,再通过getMoreResults()来获取其他的结果集。
下面是这些方法的签名,可以在statement.h头文件中查阅Statement的完整方法列表。

[cpp] view plaincopy
  1. /* connection.h */
  2. void Connection::setSchema(const std::string& catalog);
  3. /* statement.h */
  4. ResultSet* Statement::executeQuery (const std::string& sql);
  5. int Statement::executeUpdate (const std::string& sql);
  6. bool Statement::execute (const std::string& sql);
  7. ResultSet* Statement::getResultSet();
  8. uint64_t Statement::getUpdateCount();
这些方法出错时都会抛出SQLException异常,所以在你的代码中应该使用try...catch语句块来捕获这些异常。

现在回顾上面那个完全的例子,你会发现获取City表的所有记录是如此的简单:

[cpp] view plaincopy
  1. Statement *stmt;
  2. ResultSet *res;
  3. res = stmt -> executeQuery ("SELECT * FROM City");
executeQuery方法返回ResultSet对象,它包含了查询的结果。在以下情况下,executeQuery会抛出SQLException异常:数据库在执行查询时出错;在一个关闭的Statement对象上调用executeQuery;给出的SQL语句返回的不是一个简单的结果集;
上面的代码可以用Statement::execute()重写:

[cpp] view plaincopy
  1. bool retvalue = stmt -> execute ("SELECT * FROM City");
  2. if (retvalue)
  3. {
  4. res = stmt -> getResultSet();
  5. }
  6. else
  7. {
  8. ...
  9. }

execute()返回True表示操作的结果是一个ResultSet对象,否则结果是受影响记录的数量或没有结果。当返回True时,通过getResultSet方法获取结果集,在返回False的情况下调用getResultSet方法,将返回NULL。

当数据库在执行时发生错误或者在一个已关闭的Statement对象上执行execute与getResultSet方法,都会抛出SQLException异常。
如果要往数据库里添加一条新的记录,可以像下面的例子一样简单的调用executeUpdate方法:
[cpp] view plaincopy
  1. int updateCount = stmt -> executeUpdate ("INSERT INTO City (CityName) VALUES ('Napier, New Zealand')");
如果executeUpdate执行的是像INSERT, UPDATE或DELETE这样的数据操作语句(DML),它返回受影响的记录的数量;如果执行的是数据定义语句(DDL),它返回0。在数据库操作失败,或者在一个已经关闭的Statement上调用该方法,或者给出的SQL语句是一个查询语句(会返回结果集),该方法会抛出SQLException异常。
下面的代码使用execute和getUpdateCount方法来生写上面的例子:

[cpp] view plaincopy
  1. int updateCount = 0;
  2. bool retstatus = stat->execute("INSERT INTO City (CityName) VALUES ('Napier, New Zealand')");
  3. if (!retstatus)
  4. {
  5. updateCount = stat->getUpdateCount();
  6. }
  7. else
  8. {
  9. ...
  10. }
从ResultData中获取数据

上面的段落介绍了执行SQL查询的方法:executeQuery和execute,用于获取ResultSet对象。我们可以通过ResultSet访问查询的结果。每一个ResultSet都包含一个游标(cursor),它指向数据集中的当前记录行。ResultSet中排列的记录是有序的(译者注:只能按顺序一条一条获取,不能跳跃式获取)。(但)在同一行中,列值的访问却是随意的:可以通过列的位置或者名称。通过列的名称访问列值让代码更清晰,而通过位置访问列值则更高效。

列的名称通过SQL语句的AS子名设定,如果SQL语句中没有使用AS子名,列的名称默认为数据表中对应的列名。例如对于"SELECT CityName AS CN FROM City",CN就是结果集中列的名称。
    在ResultSet中的数据,可以通过getXX系列方法来获取,例如:getString(), getInt(),"XX"取决于数据的类型。next()与previous()使游标移到结果集中的下一条或上一条记录。
Statement执行SQL语句返回ResultSet对象后,ResultSet就变成一个独立的对象,与原先的Statement再也没有联系,即使Statement对象关闭,重新执行其他sql语句,或者获取多个结果集中的下一个。ResultSet将一直有效,除非显式或隐式地将其关闭。
    在撰写本文时,对于Statement对象,MySQL Connector/C++总是返回缓存结果,这些结果在客户端缓存。不管结果集数据量大小,MySQLConnector/C++ Driver总是获取所有的数据。希望以后的版本中,Statement对象能够返回缓存和非缓存的结果集。
下面是数据获取方法的签名,可以在resultset.h头文件中查看所有ResultSet类支持的方法。
[cpp] view plaincopy
  1. /* resultset.h */
  2. size_t ResultSet::rowsCount() const;
  3. void ResultSet::close();
  4. bool ResultSet::next();
  5. bool ResultSet::previous();
  6. bool ResultSet::last();
  7. bool ResultSet::first();
  8. void ResultSet::afterLast();
  9. void ResultSet::beforeFirst();
  10. bool ResultSet::isAfterLast() const;
  11. bool ResultSet::isBeforeFirst()const;
  12. bool ResultSet::isClosed() const;
  13. bool ResultSet::isNull(uint32_t columnIndex) const;
  14. bool ResultSet::isNull(const std::string& columnLabel) const;
  15. bool ResultSet::wasNull() const;
  16. std::string ResultSet::getString(uint32_t columnIndex) const;
  17. std::string ResultSet::getString(const std::string& columnLabel) const;
  18. int32_t ResultSet::getInt(uint32_t columnIndex) const;
  19. int32_t ResultSet::getInt(const std::string& columnLabel) const;

在下面的简单示例中,查询语句"SELECT * FROM City"返回的ResultSet中只包含一列:CityName,数据类型为String,对应MySQL中的VARCHAR类型。这个例子通过next方法循环从结果集中获取CityName值,并显示在控制台上:

[cpp] view plaincopy
  1. while (res -> next())
  2. cout << rs -> getString("CityName") << endl;

也可以通过位置来获取列值(位置从1开始而非从0开始),下面的代码产生相同的结果:

[cpp] view plaincopy
  1. while (res -> next())
  2. cout << rs -> getString(1) << endl;

如果数据库中该字段的值为NULL,getString将返回一个空的字符串。Result::isNull用于判断指定列在数据库中的值是否为NULL。Result::wasNULL()用于判断最近读取的列的值是否为空。

下面的例子演示了通过cursor(游标)倒序读取结果集中的数据:

[cpp] view plaincopy
  1. /* Move the cursor to the end of the ResultSet object, just after the last row */
  2. res -> afterLast();
  3. if (!res -> isAfterLast())
  4. {
  5. throw runtime_error("Error: Cursor position should be at the end of the result set after the last row.");
  6. }
  7. /* fetch the data : retrieve all the rows in the result set */
  8. while (res -> previous())
  9. {
  10. cout << rs->getString("CityName") << endl;
  11. }

getString方法在以下情况下会抛出SQLException异常:指定列名或位置不存在;数据库在执行操作时失败;在一个关闭的cursor上执行调用该方法。

转载于:https://www.cnblogs.com/sunylat/archive/2013/01/08/6119145.html

MySQL Connector/C++入门教程(上)相关推荐

  1. Mysql数据库基础入门教程

    Mysql数据库基础入门教程 课程链接:https://www.bilibili.com/video/BV1Qb411x7Yc?p=1 2022/1/22start 一.数据库简介 1.什么是数据库? ...

  2. MySQL数据库新手入门教程

    相信很多做数据分析的朋友都发现,在平时做业务分析中,Excel表格是我们使用最频繁的工具.我们还发现,Excel虽然好用,但一旦数据量大了起来,比如处理二三十万条或以上数据量的时候,就会出现卡顿,甚至 ...

  3. c mysql 视图_MySQL入门教程(七)之视图

    相关阅读: 视图是从一个或多个表中导出来的虚拟表.视图就像一个窗口,通过这个窗口可以看到系统专门提供的数据. 1.视图简介 1.1 视图的含义 视图是从一个或多个表中导出来的虚拟表,还可以从已经存在的 ...

  4. MySQL 基础知识入门教程

    前言 知识无底,学海无涯,到今天进入MySQL的学习4天了,知识点虽然简单,但是比较多,所以写一篇博客将MySQL的基础写出来,方便自己以后查找,还有就是分享给大家. 一.SQL简述 1.SQL的概述 ...

  5. SQL-Server 零基础入门教程[上]

    目录 一.数据库 (1)安装SQL-Server (2)连接服务器 (3)分离附加数据库 (4) 删除数据库(delete database) 二.数据类型 三.创建表 一.数据库 SQL在后端开发中 ...

  6. Odoo进销存(采购、销售、仓库)入门教程 - 上

    运行环境: Ubuntu14.04+Odoo8.0 作者:苏州-微尘 0. 前言 Odoo(OpenERP)作为一款优秀的开源ERP软件,开发历史已有10年之久.随着系统的发展成熟,已有越来越多的公司 ...

  7. Mybatis Plus与Mysql整合的入门教程

    开始前准备: 这是基于SpringBoot的项目,SpringBoot 2.3版本:使用工具:IDEA 2019.SQLyog10 一.首先要在已存在数据库(使用SQLyog10)中建一个实体类的表, ...

  8. mysql connector cpp_MySQL Connector/C++(一)

    如果我翻译错了或者翻译的不好,欢迎指正- Developing Database Applications Using MySQL Connector/C++ 这个教程会教你搭建安装MySQL Con ...

  9. 32位mysql安装包_《MySQL 入门教程》第 02 篇 MySQL 安装

    文章来源:<MySQL 入门教程>第 02 篇 MySQL 安装 原文作者:不剪发的Tony老师 来源平台:CSDN 上一篇我们了解了什么是MySQL数据库. 本文介绍如何在 Window ...

最新文章

  1. 360的新手机没用AI,用在了车载后视镜上
  2. Java调用ocx控件以及dll
  3. sqlserver附加数据库错误823的解决方案
  4. 云计算成IT反“腐”后盾-《中国电子报》2013年5月特刊
  5. Eclipse导入项目常见问题----jdk版本问题(有个红色感叹号)01
  6. 亲手搭建一个基于Asp.Net WebApi的项目基础框架1
  7. 在navicat中新建数据库
  8. java 的io流需要学吗_Java Io流怎么学习呢?
  9. Silver Cow Party(POJ-3268)
  10. 什么是应用管理与运维平台(ServiceStage)?
  11. sqlserver数据库备份
  12. 总结nodejs的优缺点
  13. PCL之点云可视化--CloudViewer
  14. zk临时节点失效时间_dubbo学习(六)服务发布dubbo服务在zk的创建、订阅
  15. 桌面便签软件下载,电脑桌面便签软件下载哪一个
  16. ubuntu安装github 3D渲染库dirt
  17. outlook邮箱收件服务器密码,outlook邮箱 收件服务器
  18. Android视频列表自动播放功能
  19. 在多台终端设备的i茅台应用中,实现同时自动化预约X酒的解决方案
  20. 学习笔记 | 零基础平面设计入门

热门文章

  1. birt中文手册在线_QGIS简体中文翻译现状
  2. 嵌入式Linux入门5:移植总览
  3. PotPlayer:最强播放器,无边框
  4. 【java】LongAdder源码分析原理分析
  5. 【clickhouse】clickhouse的系统表
  6. 【Elasticsearch】如何使用 Elasticsearch 6.2 搜索中文、日文和韩文文本 - 第 2 部分: 多字段
  7. 【SpringClould】SpringClould eureka 单机与集群搭建
  8. 【Es】Es 集群设置分片很大导致集群无法选举主节点异常等
  9. 【Elasticsearch】Elasticsearch 索引 模板 template
  10. 【Docker】Docker 安装 Prometheus并且交给 grafana