Apacheモジュールの mod_dbd を試してみます。
mod_dbd はデータベースへのコネクション管理機能を提供するモジュール。
内部で apr_dbd を用いてコネクションプール機能を提供するラッパーモジュールとなっていて、
データベースへの各問い合わせは apr_dbd のAPIを利用します。
Apache Portable Runtime: DBD routines
今回は以下のようなテーブル(dbd_test.user)を対象に dbdtest_module を作ります。
(環境: Apache/2.2.17, APR 1.3.12, APR-Util 1.3.9)
* user *
| id | name | age |
| 1 | foo | 10 |
| 2 | bar | 20 |
* テンプレート作成
1 2 3 4 5 6 7 |
$ apxs -g -n dbdtest Creating [DIR] dbdtest Creating [FILE] dbdtest/Makefile Creating [FILE] dbdtest/modules.mk Creating [FILE] dbdtest/mod_dbdtest.c Creating [FILE] dbdtest/.deps $ cd dbdtest |
* mod_dbdtest.c を編集
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
#include "httpd.h" #include "http_config.h" #include "http_protocol.h" #include "ap_config.h" #include "apr_dbd.h" #include "mod_dbd.h" #include "apr_string.h" /* The sample content handler */ static int dbdtest_handler(request_rec *r) { if(strcmp(r->handler, "dbdtest")) { return DECLINED; } r->content_type = "text/html"; if(!r->header_only) ap_rputs("The sample page from mod_dbdtest.c<br />", r); apr_dbd_results_t* res = NULL; apr_dbd_row_t* row = NULL; apr_dbd_prepare_t* stmt = NULL; ap_dbd_t* dbd = NULL; int errno; const char* query = "SELECT * FROM user"; // データベースへのコネクション確立 if((dbd = ap_dbd_acquire(r)) == NULL) { ap_rputs("db handle acquire failed.", r); return HTTP_INTERNAL_SERVER_ERROR; } // DBドライバ名を取得 ap_rprintf(r, "DBD driver name is %s<br />", apr_dbd_name(dbd->driver)); // ステートメントの準備 errno = apr_dbd_prepare(dbd->driver, r->pool, dbd->handle, query, NULL, &stmt); if(errno != 0) { ap_rprintf(r, "Error %d %s", errno, apr_dbd_error(dbd->driver, dbd->handle, errno)); return OK; } // 参照系のSQLを発行, 更新系の場合は apr_dbd_pquery を利用する errno = apr_dbd_pselect(dbd->driver, r->pool, dbd->handle, &res, stmt, 0, 0, NULL); if(errno != 0) { ap_rprintf(r, "Error %d %s", errno, apr_dbd_error(dbd->driver, dbd->handle, errno)); return OK; } // 1レコードを取得 while(apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1) != -1) { // データの取得、添え字の0は最初のカラムを指す char* id = apr_dbd_get_entry(dbd->driver, row, 0); char* name = apr_dbd_get_entry(dbd->driver, row, 1); char* age = apr_dbd_get_entry(dbd->driver, row, 2); ap_rprintf(r, "id: %s, name: %s, age: %s<br />", id, name, age); } return OK; } static void dbdtest_register_hooks(apr_pool_t *p) { ap_hook_handler(dbdtest_handler, NULL, NULL, APR_HOOK_MIDDLE); } /* Dispatch list for API hooks */ module AP_MODULE_DECLARE_DATA dbdtest_module = { STANDARD20_MODULE_STUFF, NULL, /* create per-dir config structures */ NULL, /* merge per-dir config structures */ NULL, /* create per-server config structures */ NULL, /* merge per-server config structures */ NULL, /* table of config file commands */ dbdtest_register_hooks /* register hooks */ }; |
* mod_dbdtest.conf を作成
1 2 3 4 5 6 7 8 9 10 11 12 |
LoadModule dbdtest_module modules/mod_dbdtest.so <Location "/dbdtest"> SetHandler dbdtest </Location> DBDriver mysql DBDParams "host=localhost port=3306 user=ユーザ名 pass=パスワード dbname=dbd_test" DBDPersist On DBDKeep 5 DBDMax 10 DBDMin 3 DBDExptime 600 |
* インストール
1 2 3 4 5 |
$ sudo cp mod_dbdtest.conf (設定ファイルのインストールディレクトリ) $ make $ sudo make install $ sudo apachectl configtest $ sudo apachectl restart |
* 出力結果 (/dbdtest にアクセス)
1 2 3 4 |
The sample page from mod_dbdtest.c DBD driver name is mysql id: 1, name: foo, age: 10 id: 2, name: bar, age: 20 |
モジュール作成の手順としては、
1. ap_dbd_acquire 関数を用いてコネクションハンドラを取得
(ap_dbd_t 構造体の中の apr_dbd_t がコネクションハンドラ)
2. apr_dbd の各APIを用いてデータベースを操作
型名が ap_dbd だったり、apr_dbd だったり紛らわしいので注意。。
r が付いていないのが mod_dbd が提供するAPIです。
* 問題点(わからない所)
通常のSQL文を発行する場合は問題ありませんでしたが、ストアドプロシージャをCALLすると、
“PROCEDURE proc_name can’t return a result set inn the given context.”
というエラー(1312)が発生しました。。
確か、libmysqlclientを使ってプロシージャコールをするときも、
オプションを付けてmysql_real_connect()しないとダメだった気がします。
mod_dbdの場合はどうすればいいんだろう。。要調査。
あと、Apacheモジュールについてはwikiの方にもメモを残すことにしました。
Apache – Tech Note
* 参考
漢(オトコ)のコンピュータ道: mod_dbd入門編