#はじめに
本記事は Hatena Blog に投稿した以下の記事について再びまとめたものになります.
思った以上にアクセスが伸びていたため,より分かりやすい形式で Qiita に投稿しようと思いました.
内容はあまり変更せず,(1)MySQL への接続方法と(2)データベースに対する操作についてまとめます.
詳しくは以下の Document を参照していただければと思います.
#MySQL
MySQL はオープンソースで公開されている RDBMS の1つです.
C++ のプログラムから MySQL に接続するには Connector/C++ を用います.
以下のリンクからダウンロード可能なので,OS に応じて適切なものを選択してください.
また,本記事では MySQL と Connector/C++ のインストール方法や,SQL 構文については省略します.
#Connector/C++
それでは C++ のプログラムから MySQL に接続する方法を解説していきます.
処理の流れの概要は次の通りになります.
-
ドライバの生成
-
ドライバを用いてデータベースに接続
-
データベースに対して処理を行う
1 と 2 は API を用いて各1行で記述することができるため,3 の処理について詳しく解説したいと思います.
まず,実際に Connector/C++ で MySQL に対して処理を行うプログラムを添付します.
#include <iostream>
#include <sstream>
#include <memory>
#include <mysql_driver.h>
#include <mysql_connection.h>
#include <mysql_error.h>
#include <cppconn/Statement.h>
#include <cppconn/ResultSet.h>
//define your own configurations in mysql_config.hpp
//for example: HOST = "tcp://127.0.0.1:3306", USER = "root", PASSWORD = "password"
// DATABASE = "database_name"
#include "mysql_config.hpp"
using namespace std;
int main()
{
try {
sql::mysql::MySQL_Driver *driver = sql::mysql::get_mysql_driver_instance();
unique_ptr<sql::Connection> con(driver->connect(HOST, USER, PASSWORD));
unique_ptr<sql::Statement> stmt(con->createStatement());
stmt->execute("USE " + DATABASE);
stmt->execute("DROP TABLE IF EXISTS conference");
stmt->execute("CREATE TABLE conference(cid int, name varchar(10))");
cout << "\"conference\" table has been created." << endl;
stmt->execute("INSERT INTO conference VALUES(1, 'SIGMOD')");
stmt->execute("INSERT INTO conference VALUES(2, 'VLDB')");
stmt->execute("INSERT INTO conference VALUES(3, 'ICDE')");
stmt->execute("INSERT INTO conference VALUES(4, 'KDD')");
unique_ptr<sql::ResultSet> res(stmt->executeQuery("SELECT * FROM conference"));
size_t row = 0;
while (res->next()) {
cout << row << "\t";
/* You can use either numeric offsets... */
cout << "cid = " << res->getInt(1);
/* ... or column names for accessing results. The latter is recommended. */
cout << ", name = '" << res->getString("name") << "' " << endl;
row++;
}
} catch (sql::SQLException &e) {
cout << "# ERR: SQLException in " << __FILE__ << " on line " << __LINE__ << endl;
cout << "# ERR: " << e.what() << endl;
cout << " (MySQL error code: " << e.getErrorCode();
cout << ", SQLState: " << e.getSQLState() << " )" << endl;
return EXIT_FAILURE;
} catch (runtime_error &e) {
cout << "# ERR: runtime_error in " << __FILE__ << " on line " << __LINE__ << endl;
cout << "# ERR: " << e.what() << endl;
return EXIT_FAILURE;
}
}
このプログラムはデータベースに以下に示すテーブルを作成し,全ての要素を取得するものになっています.
cid | name |
---|---|
1 | SIGMOD |
2 | VLDB |
3 | ICDE |
4 | KDD |
具体的には,conference TABLE を CREATE し,4つの VALUES を INSERT します.
最後にすべての要素を SELECT し,データを列挙します.
##ドライバの生成とデータベースへの接続
ドライバの生成はプログラムの19行目,データベースへの接続は20行目で行っています.
19: sql::mysql::MySQL_Driver *driver = sql::mysql::get_mysql_driver_instance();
20: unique_ptr<sql::Connection> con(driver->connect(HOST, USER, PASSWORD));
get_mysql_driver_instance() によってドライバを生成し,取得したドライバを用いて connect() でデータベースへと接続しています.
(connect() の戻り値である sql::Connection は最終的に解放する必要があるため,ここでは unique_ptr を使用しています.)
##データベースに対して処理を行う
データベースに対する処理は大きく分けて,(1)結果が返ってこない処理,(2)結果が返ってくる処理の2つに分類することができます.
(1)は INSERT,(2)は SELECT といった処理が該当します.
Connector/C++ では(1)と(2)について,それぞれ execute() 関数と executeQuery() 関数を用いて実行します.
まず前準備として,sql::Statement インスタンスを生成します.
unique_ptr<sql::Statement> stmt(con->createStatement());
execute() と executeQuery() は sql::Statement のメンバ関数なので,以降の処理は stmt から実行します.
###execute()
execute() 関数を用いてテーブルの作成,データの挿入を行う例について説明します.
上記のプログラムでは 24~32 行目に該当します.
stmt->execute("USE " + DATABASE);
stmt->execute("DROP TABLE IF EXISTS conference");
stmt->execute("CREATE TABLE conference(cid int, name varchar(10))");
cout << "\"conference\" table has been created." << endl;
stmt->execute("INSERT INTO conference VALUES(1, 'SIGMOD')");
stmt->execute("INSERT INTO conference VALUES(2, 'VLDB')");
stmt->execute("INSERT INTO conference VALUES(3, 'ICDE')");
stmt->execute("INSERT INTO conference VALUES(4, 'KDD')");
前半4行がテーブルの作成,後半4行がデータの挿入です.
execute() 関数の引数には SQL クエリをそのまま記述することができます.
###executeQuery()
続いて,executeQuery() 関数を用いてデータの取得をする例について説明します.
上記プログラムでは 34~44 行目に該当します.
unique_ptr<sql::ResultSet> res(stmt->executeQuery("SELECT * FROM conference"));
size_t row = 0;
while (res->next()) {
cout << row << "\t";
/* You can use either numeric offsets... */
cout << "cid = " << res->getInt(1);
/* ... or column names for accessing results. The latter is recommended. */
cout << ", name = '" << res->getString("name") << "' " << endl;
row++;
}
executeQuery() を実行すると,sql::ResultSet インスタンスが返されます.
このとき,execute() と同様に executeQuery() の引数には SQL クエリをそのまま記述することができます.
取得したデータへのアクセスは, getXX() 関数を用います.
このプログラムの例ですと,Int 型の cid と String 型の name の2つの要素があるため,それぞれ getInt() と getString() を用いて結果を取得します.
また,getInt() の引数は列番号であり,getString() の引数は attribute 名を指定します.
※列番号は 1 から始まります.
#まとめ
Connector/C++ を用いて MySQL に接続する方法を,実際にプログラムを用いて紹介しました.
処理の流れの概要は,
- ドライバの生成
- データベースに接続
- データベースに処理を行う
でした.
1 と 2 に関しては API を用いて簡単に記述でき,3 の処理に関しても execute() や executeQuery() 関数に SQL クエリを渡すことによって簡単に実行することができました.