C++ から MySQL に接続する

  • 7
    いいね
  • 0
    コメント

はじめに

本記事は Hatena Blog に投稿した以下の記事について再びまとめたものになります.

C++ から MySQL のデータベースに接続する

思った以上にアクセスが伸びていたため,より分かりやすい形式で Qiita に投稿しようと思いました.

内容はあまり変更せず,(1)MySQL への接続方法と(2)データベースに対する操作についてまとめます.

詳しくは以下の Document を参照していただければと思います.

https://dev.mysql.com/doc/connector-cpp/en/connector-cpp-getting-started-examples.html

MySQL

MySQL はオープンソースで公開されている RDBMS の1つです.

C++ のプログラムから MySQL に接続するには Connector/C++ を用います.
以下のリンクからダウンロード可能なので,OS に応じて適切なものを選択してください.

https://dev.mysql.com/downloads/connector/cpp/

また,本記事では MySQL と Connector/C++ のインストール方法や,SQL 構文については省略します.

Connector/C++

それでは C++ のプログラムから MySQL に接続する方法を解説していきます.

処理の流れの概要は次の通りになります.

  1. ドライバの生成

  2. ドライバを用いてデータベースに接続

  3. データベースに対して処理を行う

1 と 2 は API を用いて各1行で記述することができるため,3 の処理について詳しく解説したいと思います.

まず,実際に Connector/C++ で MySQL に対して処理を行うプログラムを添付します.

https://gist.github.com/tomov3/4509b0098673a474b2722ddb3dd337ff

connect_mysql.cpp
#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. データベースに接続
  3. データベースに処理を行う

でした.

1 と 2 に関しては API を用いて簡単に記述でき,3 の処理に関しても execute() や executeQuery() 関数に SQL クエリを渡すことによって簡単に実行することができました.