node.js + mysql 非同期ではない処理

4,546 views
Skip to first unread message

koexuka

unread,
Jun 15, 2011, 6:27:09 AM6/15/11
to nodejs_jp
はじめまして、koexukaです。
最近node.jsを使いwebアプリを開発し始めました。

そこで早速質問なのですが(ココで質問して良いのかどうかも分からず、もし場違いであればご指摘ください)、
1)クライアントからのリクエストをnode.js(expressを使っています)で受け取り
2)そのパラメータをキーにMySQLからデータを取得
3)さらに2)で取得された値を元にさらにMySQLからデータを取得し返す
という処理で行き詰っています。
MySQLの処理は、
さくらたんどっとびーず(http://sakuratan.biz/archives/3101)で紹介されているmysqlモジュールの
Clientライブラリを利用しています。
https://github.com/felixge/node-mysql

MySQLの処理が非同期で行われるため
「2)データ取得 → 3)その値を元に」という処理が動作しません。
# 厳密には2)でデータ取得される前に3)の処理へ移ってしまう

みなさんはこのような処理の場合、どのように対処されているのでしょうか。
上記MySQLライブラリに同期を保ちつつ処理を行うメソッドがあるのか、他のMySQLライブラリでは同期処理がされるのか、自作されているの
か。。。

今私で考えられる対処法は、
サーバ上にperlなりphpなりでDBからデータ取得をする実行ファイルを作り
nodeのChildProcessesクラスを使ってそのファイルを実行するという方法です。
# まだ試していませんが :(


ものすごく初心者な質問だとは思いますが、もしお分かりの方おられましたらヒントを頂ければと思います。

よろしくお願い致します。

--
Chihiro Koexuka
koe...@gmail.com

Koichi Kobayashi

unread,
Jun 15, 2011, 7:00:03 AM6/15/11
to node...@googlegroups.com
小林 (koichik) です.

> # 厳密には2)でデータ取得される前に3)の処理へ移ってしまう

3) の処理を、2) のコールバック関数の中に書きましょう。

// 2)
var sql2 = 'select ...';
client.query(sql2, function(err, results, fields) {
// 3)
var sql3 = 'select ...'
client.query(sql3, function(err, result, fields) {
// 4) 画面を返すとか
});
});


Date: Wed, 15 Jun 2011 03:27:09 -0700 (PDT)
From: koexuka <koe...@gmail.com>
Subject: [nodejs_jp:320] node.js + mysql 非同期ではない処理

--
{
name: "Koichi Kobayashi",
mail: "koi...@improvement.jp",
blog: "http://d.hatena.ne.jp/koichik/",
twitter: "@koichik"
}

Toshihiro Shimizu

unread,
Jun 15, 2011, 7:00:16 AM6/15/11
to node...@googlegroups.com
mesoです。

恐らく今のコードは2)と3)のclient.query()を並べて書いている感じになっているのだと思います。
そうではなく、client.query()の引数にcallback関数を指定して

client.query('select id from foo', function(err, results, fields) { // 2)の取得
var fooId = results[0].id;
client.query('select data from bar where foo_id = ?', [fooId],
function(err, results, fields) { // 3)の取得
var data = results[0].data;
// dataを使った処理
});
});
みたいな感じに、2)の処理の中に3)の処理をネストして記述するという形にすれば大丈夫です。

これが多くなるとどんどんネストが深くなっていくので、その際は
http://www.infoq.com/jp/articles/surviving-asynchronous-programming-in-javascript
に出ているようなモジュールを使って工夫することになると思います。

2011/6/15 koexuka <koe...@gmail.com>:

--
Toshihiro Shimizu / @meso

koexuka

unread,
Jun 15, 2011, 7:16:46 AM6/15/11
to nodejs_jp
koichikさん、mesoさん
早速の返信ありがとうございます。

mesoさんのおっしゃるとおり、2)と3)のclient.queryを並べて書いています。
お二人のご指摘のように2)のコールバック内に3)のコールバックを含めて試してみます。
# すみません、只今出てしまっており確認が出来ません :(

もう一つ同様の質問ですが、
例えばユーザ認証を以下のように行いたい場合

----------------- app.js --------------------
if (MyOriginalModule.isAuth(req.userId)) {
// 認証OKだったらの処理
}

------------------ MyOriginalModule.js --------------------
module.exports.isAuth = function(userId) {
// MySQLへ接続し、userIdが存在するかどうか認証を行う。
// @return boolean 認証OK...true 認証NG...false
}

これも同様に非同期なため、結果を取得できません。
表現がオカシイですね、、結果を取得できませんというより
MySQLへ接続し、クエリ結果からtrue/falseを返すような自作モジュール(または関数)を作りたいのですが
この場合はどのような処理になりますでしょうか。


立て続けに質問で本当に申し訳ございません。
また、もしお手すきの時に返信頂ければと思います。

よろしくお願い致します。

On 6月15日, 午後8:00, Toshihiro Shimizu <shimizu.toshih...@gmail.com>
wrote:
> mesoです。
>
> 恐らく今のコードは2)と3)のclient.query()を並べて書いている感じになっているのだと思います。
> そうではなく、client.query()の引数にcallback関数を指定して
>
> client.query('select id from foo', function(err, results, fields) { // 2)の取得
> var fooId = results[0].id;
> client.query('select data from bar where foo_id = ?', [fooId],
> function(err, results, fields) { // 3)の取得
> var data = results[0].data;
> // dataを使った処理
> });});
>
> みたいな感じに、2)の処理の中に3)の処理をネストして記述するという形にすれば大丈夫です。
>
> これが多くなるとどんどんネストが深くなっていくので、その際はhttp://www.infoq.com/jp/articles/surviving-asynchronous-programming-i...
> に出ているようなモジュールを使って工夫することになると思います。
>
> 2011/6/15 koexuka <koex...@gmail.com>:
> > koex...@gmail.com

Koichi Kobayashi

unread,
Jun 15, 2011, 7:30:24 AM6/15/11
to node...@googlegroups.com
小林 (koichik) です.

非同期ではない、戻り値を返す API:

var result = MyOriginalModule.isAuth(req.userId);
if (result) {
...
}

は、次のように非同期な API にします。

MyOriginalModule.isAuth(req.userId, function(err, result) {
if (result) {
...
}
});

Node の世界では、非同期な API には次の約束に従うことになってます。

・非同期 API は最後の引数でコールバック関数を受け取る。
・コールバック関数の最初の引数でエラーを示す (エラーがない場合は null)。

標準モジュールでは、ファイルシステムの API が参考になります。

http://nodejs.jp/nodejs.org_ja/api/fs.html


isAuth() の実装では、

module.exports.isAuth = function(userId, callback) {
// MySQLへ接続し、userIdが存在するかどうか認証を行う。
client.query(sql, function(err, result, fields) {
if (err) {
// エラー
return callback(err);
}
if (...) {
//認証OK
callback(null, true);
} else {
//認証NG
callback(null, false);
}
});
}

のように、MySQL にアクセスしたコールバック関数の中で、
引数で受け取ったコールバック関数を呼び出します。

Date: Wed, 15 Jun 2011 04:16:46 -0700 (PDT)
From: koexuka <koe...@gmail.com>
Subject: [nodejs_jp:325] Re: node.js + mysql 非同期ではない処理

--

koexuka

unread,
Jun 16, 2011, 11:53:50 AM6/16/11
to nodejs_jp
koichikさん
koexukaです。

なるほど!
目からウロコ落ちてる間に実装出来ました。

nodeは基本的に非同期で処理されるということがよく分かりました。
というかなんとなく言語仕様が理解できました。

今自分で思いついたnodeアプリを開発していて
かなり完成に近づきました。
# 近づいた気になってるだけかもですが^^;


これからもよろしくお願いします。
> From: koexuka <koex...@gmail.com>
> mail: "koic...@improvement.jp",
Reply all
Reply to author
Forward
0 new messages