原文地址:http://dev.mysql.com/tech-resources/articles/mysql-connector-cpp.html#trx
Create Table: CREATE TABLE `City` ( `CityName` varchar(30) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=ascii
下面的代码演示如何使用Connector/C++连接到MySQL服务器:
#include <iostream> #include <map> #include <string> #include <memory> #include "mysql_driver.h" #include "mysql_connection.h" #include "cppconn/driver.h" #include "cppconn/statement.h" #include "cppconn/prepared_statement.h" #include "cppconn/metadata.h" #include "cppconn/exception.h" #define DBHOST "tcp://127.0.0.1:3306" #define USER "root" #define PASSWORD "000000" #define DATABASE "test" #define NUMOFFSET 100 #define COLNAME 200 using namespace std; using namespace sql; #pragma comment(lib, "mysqlcppconn.lib") void Demo(); int main(int argc, char *argv[]) { Demo(); return 0; } /* 获取数据库信息 */ static void GetDBMetaData(Connection *dbcon) { if (dbcon->isClosed()) { throw runtime_error("DatabaseMetaData FAILURE - database connection closed"); } cout << "\nDatabase Metadata" << endl; cout << "-----------------" << endl; cout << boolalpha; /* The following commented statement won't work with Connector/C++ 1.0.5 and later */ //auto_ptr < DatabaseMetaData > dbcon_meta (dbcon->getMetaData()); DatabaseMetaData *dbcon_meta = dbcon->getMetaData(); cout << "Database Product Name: " << dbcon_meta->getDatabaseProductName() << endl; cout << "Database Product Version: " << dbcon_meta->getDatabaseProductVersion() << endl; cout << "Database User Name: " << dbcon_meta->getUserName() << endl << endl; cout << "Driver name: " << dbcon_meta->getDriverName() << endl; cout << "Driver version: " << dbcon_meta->getDriverVersion() << endl << endl; cout << "Database in Read-Only Mode?: " << dbcon_meta->isReadOnly() << endl; cout << "Supports Transactions?: " << dbcon_meta->supportsTransactions() << endl; cout << "Supports DML Transactions only?: " << dbcon_meta->supportsDataManipulationTransactionsOnly() << endl; cout << "Supports Batch Updates?: " << dbcon_meta->supportsBatchUpdates() << endl; cout << "Supports Outer Joins?: " << dbcon_meta->supportsOuterJoins() << endl; cout << "Supports Multiple Transactions?: " << dbcon_meta->supportsMultipleTransactions() << endl; cout << "Supports Named Parameters?: " << dbcon_meta->supportsNamedParameters() << endl; cout << "Supports Statement Pooling?: " << dbcon_meta->supportsStatementPooling() << endl; cout << "Supports Stored Procedures?: " << dbcon_meta->supportsStoredProcedures() << endl; cout << "Supports Union?: " << dbcon_meta->supportsUnion() << endl << endl; cout << "Maximum Connections: " << dbcon_meta->getMaxConnections() << endl; cout << "Maximum Columns per Table: " << dbcon_meta->getMaxColumnsInTable() << endl; cout << "Maximum Columns per Index: " << dbcon_meta->getMaxColumnsInIndex() << endl; cout << "Maximum Row Size per Table: " << dbcon_meta->getMaxRowSize() << " bytes" << endl; cout << "\nDatabase schemas: " << endl; auto_ptr < ResultSet > rs ( dbcon_meta->getSchemas()); cout << "\nTotal number of schemas = " << rs->rowsCount() << endl; cout << endl; int row = 1; while (rs->next()) { cout << "\t" << row << ". " << rs->getString("TABLE_SCHEM") << endl; ++row; } // while cout << endl << endl; } /* 获取结果集信息 */ static void GetResultDataMetaBata(ResultSet *rs) { if (rs -> rowsCount() == 0) { throw runtime_error("ResultSetMetaData FAILURE - no records in the result set"); } cout << "ResultSet Metadata" << endl; cout << "------------------" << endl; /* The following commented statement won't work with Connector/C++ 1.0.5 and later */ //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 << endl; cout.width(20); cout << "Column Name/Label"; cout.width(20); cout << "Column Type"; cout.width(20); cout << "Column Size" << endl; for (int i = 0; i < numcols; ++i) { 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 << 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 << endl; } /* 打印结果集中的数据 */ static void RetrieveDataAndPrint(ResultSet *rs, int type, int colidx, string colname) { /* retrieve the row count in the result set */ cout << "\nRetrieved " << rs->rowsCount() << " row(s)." << endl; cout << "\nCityName" << endl; cout << "--------" << endl; /* fetch the data : retrieve all the rows in the result set */ while (rs->next()) { if (type == NUMOFFSET) { cout << rs -> getString(colidx) << endl; } else if (type == COLNAME) { cout << rs -> getString(colname) << endl; } // if-else } // while cout << endl; } void Demo() { 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(DBHOST); const string user(USER); const string password(PASSWORD); const string database(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() << endl; /* select appropriate database schema */ con -> setSchema(database); /* retrieve and display the database metadata */ GetDBMetaData(con); /* create a statement object */ stmt = con -> createStatement(); cout << "Executing the Query: \"SELECT * FROM City\" .." << endl; /* run a query which returns exactly one result set */ res = stmt -> executeQuery ("SELECT * FROM City"); cout << "Retrieving the result set .." << endl; /* retrieve the data from the result set and display on stdout */ RetrieveDataAndPrint (res, NUMOFFSET, 1, string("CityName")); /* retrieve and display the result set metadata */ GetResultDataMetaBata (res); cout << "Demonstrating Prepared Statements .. " << endl << endl; /* insert couple of rows of data into City table using Prepared Statements */ prep_stmt = con -> prepareStatement ("INSERT INTO City (CityName) VALUES (?)"); cout << "\tInserting \"London, UK\" into the table, City .." << endl; prep_stmt -> setString (1, "London, UK"); updatecount = prep_stmt -> executeUpdate(); cout << "\tCreating a save point \"SAVEPT1\" .." << endl; savept = con -> setSavepoint ("SAVEPT1"); cout << "\tInserting \"Paris, France\" into the table, City .." << endl; prep_stmt -> setString (1, "Paris, France"); updatecount = prep_stmt -> executeUpdate(); cout << "\tRolling back until the last save point \"SAVEPT1\" .." << endl; con -> rollback (savept); con -> releaseSavepoint (savept); cout << "\tCommitting outstanding updates to the database .." << endl; con -> commit(); cout << "\nQuerying the City table again .." << endl; /* re-use result set object */ res = NULL; res = stmt -> executeQuery ("SELECT * FROM City"); /* retrieve the data from the result set and display on stdout */ RetrieveDataAndPrint(res, COLNAME, 1, string ("CityName")); cout << "Cleaning up the resources .." << endl; /* Clean up */ delete res; delete stmt; delete prep_stmt; con -> close(); delete con; } catch (SQLException &e) { cout << "ERROR: " << e.what(); cout << " (MySQL error code: " << e.getErrorCode(); cout << ", SQLState: " << e.getSQLState() << ")" << endl; if (e.getErrorCode() == 1047) { /* Error: 1047 SQLSTATE: 08S01 (ER_UNKNOWN_COM_ERROR) Message: Unknown command */ cout << "\nYour server does not seem to support Prepared Statements at all. "; cout << "Perhaps MYSQL < 4.1?" << endl; } return; } catch (std::runtime_error &e) { cout << "ERROR: " << e.what() << endl; return; } return; }
/* mysql_driver.h */ MySQL_Driver *sql::mysql::get_mysql_driver_instance() /* mysql_driver.h */ sql::Connection * connect(const std::string& hostName, const std::string& userName, const std::string& password); sql::Connection * connect(std::map<std::string, sql::ConnectPropertyVal> & options);
sql::mysql::MySQL_Driver *driver = 0; sql::Connection *conn = 0; try { driver = sql::mysql::get_mysql_driver_instance(); conn = driver->connect("tcp://localhost:3306/test", "root", "000000"); cout << "连接成功" << endl; } catch (...) { cout << "连接失败" << endl; } if (conn != 0) { delete conn; }
sql::mysql::MySQL_Driver *driver = 0; sql::Connection *conn = 0; std::map<std::string, ConnectPropertyVal> connProperties; ConnectPropertyVal tmp; tmp.str.val = "tcp://127.0.0.1:3306/test"; connProperties[std::string("hostName")] = tmp; tmp.str.val = "root"; connProperties[std::string("userName")] = tmp; tmp.str.val = "000000"; connProperties[std::string("password")] = tmp; try { driver = sql::mysql::get_mysql_driver_instance(); conn = driver -> connect(connProperties); cout << "连接成功" << endl; } catch(...) { cout << "连接失败" << endl; } if (conn != 0) { delete conn; }
sql::Connection *conn = driver -> connect("tcp://127.0.0.1:3306", "root", "000000"); // do something delete conn
use namespace std; use namespace sql; auto_ptr < Connection > con ( driver -> connect("tcp://127.0.0.1:3306", "root", "000000") );
/* connection.h */ Statement* Connection::createStatement();
Connection *conn; // Connection对象的引用 Statement *stat; Statement stat = conn -> createStatement();
/* 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();
Statement *stmt; ResultSet *res; res = stmt -> executeQuery ("SELECT * FROM City");
bool retvalue = stmt -> execute ("SELECT * FROM City"); if (retvalue) { res = stmt -> getResultSet(); } else { ... }execute()返回True表示操作的结果是一个ResultSet对象,否则结果是受影响记录的数量或没有结果。当返回True时,通过getResultSet方法获取结果集,在返回False的情况下调用getResultSet方法,将返回NULL。
int updateCount = stmt -> executeUpdate ("INSERT INTO City (CityName) VALUES ('Napier, New Zealand')");
int updateCount = 0; bool retstatus = stat->execute("INSERT INTO City (CityName) VALUES ('Napier, New Zealand')"); if (!retstatus) { updateCount = stat->getUpdateCount(); } else { ... }
上面的段落介绍了执行SQL查询的方法:executeQuery和execute,用于获取ResultSet对象。我们可以通过ResultSet访问查询的结果。每一个ResultSet都包含一个游标(cursor),它指向数据集中的当前记录行。ResultSet中排列的记录是有序的(译者注:只能按顺序一条一条获取,不能跳跃式获取)。(但)在同一行中,列值的访问却是随意的:可以通过列的位置或者名称。通过列的名称访问列值让代码更清晰,而通过位置访问列值则更高效。
/* 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"返回的ResultSet中只包含一列:CityName,数据类型为String,对应MySQL中的VARCHAR类型。这个例子通过next方法循环从结果集中获取CityName值,并显示在控制台上:
while (res -> next()) { cout << rs -> getString("CityName") << endl; }
也可以通过位置来获取列值(位置从1开始而非从0开始),下面的代码产生相同的结果:
while (res -> next()) { cout << rs -> getString(1) << endl; }
/* 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") << endl; }
getString方法在以下情况下会抛出SQLException异常:指定列名或位置不存在;数据库在执行操作时失败;在一个关闭的cursor上执行调用该方法。
未完待续!